Giter VIP home page Giter VIP logo

jsgif's Introduction

Pure JavaScript HTML5 to (Animated) GIF Conversion

Based on as3gif Ported by Kevin Kwok

This is the raw canvas element saved as a non-animated PNG This is the GIF which was generated from the canvas. This is the GIF which was generated from the canvas.

AS3GIF lets you play and encode animated GIF's with ActionScript 3

Since web pages can usually natively play GIFs fine, it's only a port of the GIFEncoder portions of the library.

Basic Usage

Since it pretty much is GIFEncoder, you could consult the as3gif how-to page

But there are some differences so I'll cover it here anyway.

You first need to include the JS files. It's probably best if you include it in this order, but it shouldn't matter too much.

<script type="text/javascript" src="LZWEncoder.js"></script>
<script type="text/javascript" src="NeuQuant.js"></script>
<script type="text/javascript" src="GIFEncoder.js"></script>

If you want to render the gif through an inline <img> tag or try to save to disk or send to server or anything that requires conversion into a non-binary string form, you should probably include b64.js too.

<script type="text/javascript" src="b64.js"></script>

Simple enough right? Now to convert stuff to GIF, you need to have a working or at least some imageData-esque array.

<canvas id="bitmap"></canvas>
<script>
  var canvas = document.getElementById('bitmap');
  var context = canvas.getContext('2d');
  context.fillStyle = 'rgb(255,255,255)';
  context.fillRect(0,0,canvas.width, canvas.height); //GIF can't do transparent so do white
  
  context.fillStyle = "rgb(200,0,0)";  
  context.fillRect (10, 10, 75, 50);   //draw a little red box

Now we need to init the GIFEncoder.

  var encoder = new GIFEncoder();

If you are making an animated gif, you need to add the following

  encoder.setRepeat(0); //0  -> loop forever
                        //1+ -> loop n times then stop
  encoder.setDelay(500); //go to next frame every n milliseconds

Now, you need to tell the magical thing that you're gonna start inserting frames (even if it's only one).

  encoder.start();

And for the part that took the longest to port: adding a real frame.

  encoder.addFrame(context);

In the GIFEncoder version, it accepts a Bitmap. Well, that doesn't exist in Javascript (natively, anyway) so instead, I use what I feel is a decent analogue: the canvas context. However, if you're in a situation where you don't have a real <canvas> element. That's okay. You can set the second parameter to true and pass a imageData.data-esque array as your first argument. So in other words, you can do encoder.addFrame(fake_imageData, true) as an alternative. However, you must do an encoder.setSize(width, height); before you do any of the addFrames if you pass a imageData.data-like array. If you pass a canvas context, then that's all okay, because it will automagically do a setSize with the canvas width/height stuff.

Now the last part is to finalize the animation and get it for display.

  encoder.finish();
  var binary_gif = encoder.stream().getData() //notice this is different from the as3gif package!
  var data_url = 'data:image/gif;base64,'+encode64(binary_gif);

Or download the gif file directly with a given filename as

  encoder.finish();
  encoder.download("download.gif");

Docs

Each of the files exposes a single global (see, at least it's considerate!). But since there's three files, that means that there's three globals. But two of them are more of supporting libraries that I don't totally understand or care about enough to document. So I'm just gonna document GIFEncoder.

new GIFEncoder() This is super parent function. You really don't need the new keyword because It's not really even using any special inheritance pattern. It's a closure that does some var blah = exports.blah = function blah(){ for no good reason. Anyway, it returns an object with a bunch of methods that the section will be devoted to documenting. Note that I've never tested more than half of these, so good luck.

Boolean start() This writes the GIF Header and returns false if it fails.

Boolean addFrame(CanvasRenderingContext2D context) This is the magical magic behind everything. This adds a frame.

Boolean addFrame(CanvasPixelArray image, true) This is the magical magic behind everything. This adds a frame. This time you need you pass true as the second argument and then magic strikes and it loads your canvas pixel array (which can be a real array, I dont care and I think the program has learned from my constant apathy to also not care). But note that if you do, you must first manually call setSize which is happily defined just below this one.

Boolean addFrame(ImageData image, true) This adds a frame. This time you just need to pass the ImageData object that you obtained after executing getImageData on the CanvasRenderingContext2D object. And pass true as the second argument and then if the data size and the stored size matches, then it automatically loads the data or it sets the size corresponding to the parameters of the ImageData object, and loads the pixels data.

void download(filename) Download the converted gif file after conversion, with the given file name without any additional function calls or without any additional memory issues when there are large number of frames in the gif file

void setSize(width, height) Sets the canvas size. It's supposed to be private, but I'm exposing it anyway. Gets called automagically as the size of the first frame if you don't do that crappy hacky imageData.data hack.

void setDelay(int milliseconds) the number of milliseconds to wait on each frame

void setDispose(int code) Sets the GIF frame disposal code for the last added frame and any subsequent frames. Default is 0 if no transparent color has been set, otherwise 2. I have no clue what this means so I just copypasted it from the actionscript docs.

void setFrameRate(Number fps) Sets frame rate in frames per second. Equivalent to setDelay(1000/fps). I think that's stupid.

void setQuality(int quality) Sets quality of color quantization (conversion of images to the maximum 256 colors allowed by the GIF specification). Lower values (minimum = 1) produce better colors, but slow processing significantly. 10 is the default, and produces good color mapping at reasonable speeds. Values greater than 20 do not yield significant improvements in speed. BLAH BLAH BLAH. Whatever

void setRepeat(int iter) Sets the number of times the set of GIF frames should be played. Default is 1; 0 means play indefinitely. Must be invoked before the first image is added.

void setTransparent(Number color) Sets the transparent color for the last added frame and any subsequent frames. Since all colors are subject to modification in the quantization process, the color in the final palette for each frame closest to the given color becomes the transparent color for that frame. May be set to null to indicate no transparent color.

ByteArray finish() Adds final trailer to the GIF stream, if you don't call the finish method the GIF stream will not be valid.

String stream() Yay the only function that returns a non void/boolean. It's the magical stream function which should have been a getter which JS does support but I didnt' feel like making it a getter because getters are so weird and inconsistent. Like sure there's the nice pretty get thing but I think IE9/8 doesn't implement it because it's non standard or something and replaced it with a hideously ugly blah blah. So Anyway, it's a function. It returns a byteArray with three writeByte functions that you wouldn't care about and a getData() function which returns a binary string with the GIF. There's also a .bin attribute which contains an array with the binary stuff that I don't care about.

WebWorkers

The process isn't really the fastest thing ever, so you should use WebWorkers for piecing together animations more than a few frames long.

I haven't actually tried it yet, but here's some incomplete mock-JS which should be able to do stuff once you add the boring stuff like serializing and deserializing the content (actually, i have most of the serializing done but you have to deserialize that and that's really the boring part).

var frame_index,
    frame_length,
    height, 
    width,
    imageData; //get it from onmessage
    
var encoder = new GIFEncoder(); //create a new GIFEncoder for every new job
if(frame_index == 0){
  encoder.start();
}else{
  encoder.setProperties(true, true); //started, firstFrame
}
encoder.setSize(height, width);
encoder.addFrame(imageData, true);
if(frame_length == frame_index){
  encoder.finish()
}
postMessage(frame_index + encoder.stream().getData()) //on the page, search for the GIF89a to see the frame_index


var animation_parts = new Array(frame_length);
//on the handler side:

var worker = new WebWorker('blahblahblah.js');
worker.onmessage = function(e){
  //handle stuff, like get the frame_index
  animation_parts[frame_index] = frame_data;
  //check when everything else is done and then do animation_parts.join('') and have fun
}
var imdata = context.getImageData(0,0,canvas.width,canvas.height)
var len = canvas.width * canvas.height * 4;
var imarray = [];
for(var i = 0; i < len; i++){
  imarray.push(imdata[i]);
}

worker.postMessage(frame_index + ';' + frame_length + ';' + canvas.height + ';' + canvas.width + ';' + imarray.join(','))

jsgif's People

Contributors

antimatter15 avatar djcsdy avatar joncom avatar mudcube avatar naveennamani avatar revlin avatar thejbw avatar tobozo 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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

jsgif's Issues

No plugin.xml file

I'am getting the below mentioned error while trying to add plugin.
Error: ENOENT: no such file or directory, open 'C:\Users\PRASHA~1\AppData\Local
Temp\git\1480755504877\plugin.xml'
at Error (native)
at Object.fs.openSync (fs.js:549:18)
at Object.fs.readFileSync (fs.js:397:15)
at Object.module.exports.parseElementtreeSync (C:\Users\Prashanth\AppData\Ro
aming\npm\node_modules\cordova\node_modules\cordova-lib\src\util\xml-helpers.js:
118:27)
at new PluginInfo (C:\Users\Prashanth\AppData\Roaming\npm\node_modules\cordo
va\node_modules\cordova-lib\src\PluginInfo.js:320:37)
at C:\Users\Prashanth\AppData\Roaming\npm\node_modules\cordova\node_modules
cordova-lib\src\plugman\util\plugins.js:45:30
at _fulfilled (C:\Users\Prashanth\AppData\Roaming\npm\node_modules\cordova\n
ode_modules\q\q.js:787:54)
at self.promiseDispatch.done (C:\Users\Prashanth\AppData\Roaming\npm\node_mo
dules\cordova\node_modules\q\q.js:816:30)
at Promise.promise.promiseDispatch (C:\Users\Prashanth\AppData\Roaming\npm\n
ode_modules\cordova\node_modules\q\q.js:749:13)
at C:\Users\Prashanth\AppData\Roaming\npm\node_modules\cordova\node_modules
q\q.js:557:44

License

Could you add a license please, so I and the other users know how to use your code. Thanks a lot.

Fixes report

I have been trying to use this. I found some fixes. They are small, so just reporting for now. They can be probably updated much faster by some else, then me forking / changing / and PRing.

In GIFEncoder.js:

  • line 148, should be sizeSet, not sizeset, causes exception when passing ImageData
  • The following lines need to be added to the end of download() to actually make it work:

var click = document.createEvent('MouseEvents');
click.initEvent('click', true, false);
templink.dispatchEvent(click);

`addFrame` with `is_imageData=true` makes Chrome hang up

I'm now try separating jsgif process to Web Worker. This needs to pass the image data, not the whole of context.

So I used addFrame(ctx.getImageData(0,0,100,100), true) but this makes Chrome hang... Can you confirm this issue?

Thanks in advance.

Animated Gif comes out black w/ Web Workers

I'm trying to use Web Workers to handle the Gif creation, and while I could get animated Gif generation working without using the worker, once I moved everything over to the worker I can only get a black image with the specified dimensions as the output.

In my main JS:

this.gifWorker = new Worker("scripts/worker.js");

... context setup ...

toggleSnapshotRecord() {
  this.isRecording = !this.isRecording;
  $(document.body).toggleClass("is-recording");

  let interval = (this.captureSecondsDelay - 1) * 1000;
  let snapCount = 0;

  if (this.isRecording) {
    this.snapshotInterval = setInterval(() => {
      // Capture context image data at a specified interval
      // until the desired frame count is met
      this.snapshotFrames.push(this.canvasContext.getImageData(0, 0, this.outputWidth, this.outputHeight));
      snapCount = snapCount + 1;
      if (snapCount === this.captureFramesNumber)
        return this.toggleSnapshotRecord();
    }, interval);
  } else {
    clearInterval(this.snapshotInterval);

    // Send the frames and the canvas dimensions
    // to our web worker
    this.gifWorker.postMessage({
      size: [this.outputWidth, this.outputHeight],
      frames: this.snapshotFrames
    });

    this.gifWorker.onmessage = function(event) {
      console.log(event.data);
    }
  };
};

In my Web Worker:

self.addEventListener("message", function(event) {
  var data = event.data;
  var encoder = new GIFEncoder();

  encoder.setRepeat(0);
  encoder.setDelay(300);
  encoder.setSize(data.size[0], data.size[1]);
  encoder.start();
  encoder.addFrame(data.frames, true);
  encoder.finish();

  self.postMessage("data:image/gif;base64," + encode64(encoder.stream().getData()));
}, false);

What would I be missing here? Any help is much appreciated!

The encoding of the Gif fails depending on the size of the canvas

Hey there!
Wonderful work, I love using this library. :)
I've been having problems when encoding cavas contexts with very little in them.

Here is an example file:

<!DOCTYPE html>
<html>
    <head>
        <title>Gif testcase</title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

        <script src="LZWEncoder.js"></script>
        <script src="NeuQuant.js"></script>
        <script src="GIFEncoder.js"></script>
    </head>
    <body>
        <canvas id="myCanvas" width="300" height="300"></canvas>
        <script type="text/javascript">
          var myCanvas = document.getElementById('myCanvas');
          var context = myCanvas.getContext('2d');

          context.fillStyle = 'rgb(255,255,255)';
          context.fillRect(0, 0, myCanvas.width, myCanvas.height);

          context.strokeStyle = "#000000";
          context.beginPath();
          context.moveTo(5, 5);
          context.lineTo(5, 30);
          context.stroke();

          var encoder = new GIFEncoder();
          encoder.start();
          encoder.addFrame(context);
          encoder.finish();

          var binary_gif = encoder.stream().getData();
          var data_url = 'data:image/gif;base64,' + window.btoa(binary_gif);
          document.location.href = data_url;
        </script>
    </body>
</html>

This works perfecly. However, if I change the width or height attribute of my canvas, let's say to 250px:

<!DOCTYPE html>
<html>
    <head>
        <title>Gif testcase</title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

        <script src="LZWEncoder.js"></script>
        <script src="NeuQuant.js"></script>
        <script src="GIFEncoder.js"></script>
    </head>
    <body>
        <canvas id="myCanvas" width="250" height="250"></canvas>
        <script type="text/javascript">
          var myCanvas = document.getElementById('myCanvas');
          var context = myCanvas.getContext('2d');

          context.fillStyle = 'rgb(255,255,255)';
          context.fillRect(0, 0, myCanvas.width, myCanvas.height);

          context.strokeStyle = "#000000";
          context.beginPath();
          context.moveTo(5, 5);
          context.lineTo(5, 30);
          context.stroke();

          var encoder = new GIFEncoder();
          encoder.start();
          encoder.addFrame(context);
          encoder.finish();

          var binary_gif = encoder.stream().getData();
          var data_url = 'data:image/gif;base64,' + window.btoa(binary_gif);
          document.location.href = data_url;
        </script>
    </body>
</html>

Then the resulting gif is empty. It is encoded, however there's nothing in it. No line.

Any idea on what the problem could be?

Writing canvas to GIF outputs double speed GIF

Not sure exactly how to explain, as it seems to be a somewhat randomized issue - I'm passing a canvas element to my JS via this (as a web worker), and most of the time it's able to output a GIF just fine. Sometimes though, it spits out a GIF that seems 2x or even 3x sped up from the original source canvas (as I am putting a video on the canvas element). I know this is probably a very strange and particular use case, just posting it here in case anyone else had come across this or there was a known fix for something like this.

Data URI generates a black gif

If I add a frame with a Data URI it generates a black gif.

To reproduce

Modify clock.html demo at line 127:

uridata = canvas.toDataURL('image/png');
encoder.addFrame(uridata, true);

Data URI is generated good, you can see it if you add console.log(uridata) and the end.

Did I missed something from the docs, tho?

setTransparent

Have you gotten setTransparent(Number color) to work?

Crashes at 300+ Frames

I've written a looping animation in a canvas, and i'm trying to convert it into a gif by adding a frame every time I draw to the canvas, my animation is 360 frames long, but as soon as it reaches 300 frames, my webpage crashes, i've attached the error
image

Pixel width black line on left edge of GIF

I'm creating a 600x600 gif with image data (and using .setSize(600, 600)) and the gif looks great, but there's a pixel width black line on the left edge of the image, any idea about what's happening or how I could fix this? (note: the images being added do not have the black line)

No license information

It seems that jsgif has no information about the license of the source code.

I am not very experienced with licensing though. Original as3gif goes under the MIT license, does it means that jsgif is also MIT Licensed?

GIF almost empty

All I get is 7 bytes of data in encoder.stream().getData()
and those bytes, encoded in base64, are R0lGODlhOw==

Can please anyone help me? I need these project to work ASAP! I'm desperate! Thanks!

The script that generates all is pretty long, i'm pasting some pieces I think may be relevant, thought i think I followed the instructions to the letter, more or less.

    //draw trajectory
    ctx.lineTo(satellite.x,satellite.y);
    ctx.stroke();

    //agrega frame al gif
    if (recording)
    {
        encoder.addFrame(ctx);
        console.log('grabado frame '+steps);
    }

ctx is the canvas context. I has a white filling and the contents are few: a svg and a polligonal line (the "trajectory"). The only difference I noticed with the example file is that the example doesn't do ctx.stroke().
And the finishing code:

encoder.finish();
var binary_gif = encoder.stream().getData();
console.log(binary_gif.length+' bytes'); //gives 7
var data_url = 'data:image/gif;base64,'+btoa(binary_gif);
console.log(data_url); //gives the header and the bas64 i told you

Color Reproduction Issue

Creating an animated GIF, I'm having an issue with color reproduction. I suspect this is the quantization, as I'm able to successfully produce a screenshot from canvas using vanilla JS with no color reproduction errors.

encoder.setRepeat(0); encoder.setDelay(500); encoder.setQuality(1); encoder.start();

ah maps 2017-4-18 at 16 15 58

The logo color shifts per frame but should only be red and the radar images have on/off color blending issues.

Any advice on where to look is appreciated.

My webcam snapshot is being overlay by the gif ??

here is my situation,

I have a Web App that I'm trying to create, the concept is the following:

People take a picture on them with their Webcam / Phone Camera.

This snap is then, integrated to a gif image ( I let a transparency area to the Gif image), and those 2 images are being completed and rendered as a gif that the user can save.

So far I have all of this working, the problems I'm having are:

The render quality of the webcam snapshot is very bad in colour once is being transform in gif. I fit save in jpg or png, the quality is fine !
Somhow, the gif image is overlaying the webcam snapshot, so the webcam snapshot look terrible as you have color overlaying it and being animated.
Below is the gif I'm using: http://latitudesadventure.co.uk/webcam/assets/images/pattern/montage.gif

You can see the transparency area where the webcam snapshot is going - on the right side. The animated part of the gif ( Zebra pattern on the top) is overlaying the all image and webcam snapshot.

I believe the gif quality render may be due to that issue also.

I'm using different library to achieve this:

Webcam.js https://github.com/jhuckaby/webcamjs TO call the webcam Html2canvas https://github.com/niklasvh/html2canvas to create an image from the snapshot of the webcam Jsgif https://github.com/antimatter15/jsgif To render it as a gif, as html2canvas allow only to save in png and jpeg.

Below is my javascript which allow to save all of this:

`renderCanvasImage: function() {
setTimeout(function() {

            var encoder = new GIFEncoder();
            encoder.setRepeat(0); //auto-loop
            encoder.setDelay(1);


            // encoder.transparent = '#ffffff' ; // transparent color if given
            //   encoder.width(1500);
            encoder.start();


            html2canvas($('#holder'), {
                        onrendered: function(canvas) {
                                encoder.addFrame(canvas.getContext('2d'));
                                document.body.innerHTML = document.body.innerHTML;


                                html2canvas($('#holder'), {

                                            onrendered: function(canvas) {
                                                    encoder.addFrame(canvas.getContext('2d'));
                                                    encoder.finish();
                                                    document.body.innerHTML = document.body.innerHTML + '<img id="image" />';
                                                    document.getElementById('image').src = 'data:image/gif;base64,' + encode64(encoder.stream().getData());

                                                    html2canvas($('#holder'), {
                                                        onrendered: function(canvas) {
                                                            document.body.appendChild(canvas).id = 'hidden';
                                                            var canvas = document.getElementById('hidden');

                                                            var image = new Image();
                                                            //Create a new Image with url
                                                            image.src = canvas.toDataURL("image/gif");

                                                            // Look at URI only and assign to localStorage
                                                            imageURI = image.src;
                                                            localStorage.setItem('image', imageURI);

                                                            //****TODO better removal*/
                                                            $('#cameraContainer, .wrapperInfo, .snap').hide();

                                                            $('#result a, #result img').fadeOut(100).remove();
                                                            $(image).appendTo('#result');
                                                            $('#result').fadeIn(200);

                                                            //Send Data to DB
                                                            Lab.setData();

                                                            //PopUp Message
                                                            Lab.popupMsg();

                                                        }
                                                    });

`

And the Html:

<section id="devicePhoto">


  <div id="holder" class="text-center">

    <!-- Frame For Photo -->
    <!-- Frame For Photo -->


   <div class="snap">

    <!-- Frame Camera -->
    <!-- Frame Camera -->





       <div style="left:100px;position:relative;margin-left:160px;margin-top:60px;top:60px" id="result" class="result">
      <!-- Display Image -->
      <!-- Display Image -->
        <img src="assets/images/silouhette.png" alt="Silhouette placeholder" />
       </div>
    <!-- Generated message -->
    <!-- Generated message -->

         <div class="wrapperInfo">

             <img src="assets/images/pattern/montage.gif">

           </div>

             <div id="cameraContainer" class="result">

         <div id="webcams" style="width: 500px; height: 500px;">
         </div>

       </div>

   </div>
    <!-- PopUp Box Message -->
    <!-- PopUp Box Message -->

  </div><!-- /.end Holder -->
</section><!-- /.end Device Photo -->

I have notice, than the Gif is not being render with background but black, I m wondering if this is problem coming from ?

You can see a Live demo here ( Not compatible with Chrome, you can try with firefox / safari / IE):

http://latitudesadventure.co.uk/webcam/app.html

In the first step, enter whatever name and email, nothing is being saved from this server.

As well, once you took the snapshot, scroll down and click generate to make the gif. You will need to wait up to 5 seconds and scroll down to see the gif rendered.

Really appreciate your advise on that !

Thanks a lot !

last frame of addFrame is not added to gif

I don't have a small test-case yet, so I'll leave this a possibility, but it seems that if more than one frame is added via addFrame, the last frame is not actually added (does not display, does not exist w/in encoded gif).

If only one frame is added via addFrame, one frame exists.
If two frames are added via addFrame, one frame exists.
If three frames are added via addFrame, two frames exist.
etc.

I plan on coming up with some test code, but it might be a week or so....

Global color map

NeuQuant produce good quality color map. For local color map, it will better be for one single frame, but may cause color difference between multiple frames. Can we use a global color map here?

License?

Hi, what's the license of this library?

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.