Example #1
0
        private void RunLow()
        {
            if (m_bSavePngs)
            {
                DirectoryInfo di;
                try
                {
                    string dirname = m_GifName.Substring(0, m_GifName.Length - 4) + "_raw";
                    di = Directory.CreateDirectory(dirname);
                }
                catch (IOException)
                {
                    di = null;
                }
                if (di != null)
                {
                    for (int i = 0; i < m_Frames.Count; ++i)
                    {
                        WriteFrameAsPng(di, i);
                    }
                }
            }

            Directory.CreateDirectory(Path.GetDirectoryName(m_GifName));
            // TODO: Add back gif encoding.
            // If you wish to use a gif encoder, you should add that code in here.
            // Alternatively, you could push the frames to ffmpeg and use that instead.
            var ge = new GIFEncoder();

            ge.useGlobalColorTable = true;
            ge.repeat      = 0;
            ge.FPS         = 1000 / m_FrameDelayMs;
            ge.transparent = new Color32(255, 0, 255, 255);
            ge.dispose     = 1;

            var stream = new MemoryStream();

            ge.Start(stream);

            int nAdded = 0;
            int nTotal = m_Frames.Count;
            List <Color32[]> flippedFrames = new List <Color32[]>();

            foreach (var f in m_Frames)
            {
                var gframe = new Image(m_GifWidth, m_GifHeight, f);
                if (!flippedFrames.Contains(f))
                {
                    flippedFrames.Add(f);
                    gframe.Flip();
                }
                ge.AddFrame(gframe);
                m_CreationPercent = (float)(++nAdded) / nTotal;
            }
            ge.Finish();
            File.WriteAllBytes(m_GifName, stream.GetBuffer());
            stream.Close();
        }
        // dont we have our own encoder now??



        // X:\jsc.svn\core\ScriptCoreLib\Shared\BCLImplementation\System\Tuple.cs

        //no implementation for System.Tuple b6efdcc2-6386-375e-84aa-6732b6518b3f
        //script: error JSC1000: No implementation found for this native method, please implement [static System.Tuple.Create(System.IProgress`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=ne
        //script: warning JSC1000: Did you reference ScriptCoreLib via IAssemblyReferenceToken?
        //script: error JSC1000: error at GIFEncoderWorker..ctor,
        // assembly: U:\jsgif.Application.exe
        // type: GIFEncoderWorker, jsgif.Application, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
        // offset: 0x0049
        //  method:Void .ctor(Int32, Int32, Int32, Int32, System.Collections.Generic.IEnumerable`1[System.Byte[]], System.Action`1[System.Int32])
        //*** Compiler cannot continue... press enter to quit.


        // based on http://antimatter15.com/wp/2010/07/javascript-to-animated-gif/

        //cript: error JSC1000: No implementation found for this native method, please implement [static System.Tuple.Create(System.IProgress`1[[System.Int32,
        //cript: warning JSC1000: Did you reference ScriptCoreLib via IAssemblyReferenceToken?
        //cript: error JSC1000: error at GIFEncoderWorker..ctor,
        //assembly: V:\jsgif.Application.exe
        //type: GIFEncoderWorker, jsgif.Application, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
        //offset: 0x0049
        // method:Void .ctor(Int32, Int32, Int32, Int32, System.Collections.Generic.IEnumerable`1[System.Byte[]], System.Action`1[System.Int32])
        //** Compiler cannot continue... press enter to quit.



        /// <summary>
        /// This is a javascript application.
        /// </summary>
        /// <param name="page">HTML document rendered by the web server which can now be enhanced.</param>
        public Application(IDefault page)
        {
            // https://bugzilla.mozilla.org/show_bug.cgi?id=709490
            // http://stackoverflow.com/questions/7844886/using-webgl-from-inside-a-web-worker-is-it-possible-how

            const int x = 640;
            const int y = 480;
            // do we need automatic decomposer?

            var context = new CanvasRenderingContext2D(x, y);

            // needs to be in dom? no
            var canvas = context.canvas;


            context.fillStyle = "rgb(255,255,255)";
            context.fillRect(0, 0, canvas.width, canvas.height);

			// rebuild redux?
            var my_gradient = context.createLinearGradient(0, 0, 16, 0);
            my_gradient.addColorStop(0, "blue");
            my_gradient.addColorStop(1, "white");
            //context.fillStyle = my_gradient; //"rgb(255,255,255)";  
            context.fillStyle = "rgb(255,255,255)";  
            context.fillRect(0, 0, 16, canvas.height); //GIF can't do transparent so do white

            Action yield = delegate { };

            var r = new Random();

            Func<byte> random = r.NextByte;


            //encoder.addFrame(context);


            // 4 : 3sec
            // 8 : 0.00:00:06 
            // 16 : 0.00:00:18 

            var frames = new List<byte[]>();

            // whats the difference? should jsc switch to tyhe typed array yet?
            //var frames = new List<byte[]>();

            for (int i = 0; i < 16; i++)
            {
                context.fillStyle = "rgb(" + random() + "," + random() + "," + random() + ")";
                context.fillRect(
                    random() / 4,
                    random() / 4,
                    32 + random(),
                    32 + random()
                );

                var data = context.getImageData().data;

                //Uint8Array
                // { data = [object Uint8ClampedArray] } 
                Console.WriteLine(new { data });

                frames.Add(data);


            }

            yield += delegate
            {

            };

            new IHTMLButton { innerText = "encode!" }.AttachToDocument().WhenClicked(
                delegate
                {
                    var e = new Stopwatch();
                    e.Start();


                    Console.WriteLine("new encoder");

                    var encoder = new GIFEncoder();
                    encoder.setSize(x, y);
                    encoder.setRepeat(0); //auto-loop
                    encoder.setDelay(1000 / 15);
                    encoder.start();

                    foreach (var data in frames)
                    {
                        Console.WriteLine("addFrame");
                        encoder.addFrame((Uint8ClampedArray)(object)data, true);
                    }

                    Console.WriteLine("finish");

                    encoder.finish();

                    var bytes = Encoding.ASCII.GetBytes(encoder.stream().getData());
                    var src = "data:image/gif;base64," + Convert.ToBase64String(bytes);

                    Console.WriteLine(e.Elapsed);

                    new IHTMLImage { src = src }.AttachToDocument();
                }
            );

            new IHTMLButton { innerText = "encode via worker" }.AttachToDocument().WhenClicked(
                 delegate
                 {
                     var e = new Stopwatch();
                     e.Start();

                     var w = new Worker(
                         scope =>
                         {
                             Console.WriteLine("new encoder");

                             var encoder = new GIFEncoder();
                             encoder.setSize(x, y);
                             encoder.setRepeat(0); //auto-loop
                             encoder.setDelay(1000 / 15);
                             encoder.start();

                             scope.onmessage +=
                                 ee =>
                                 {
                                     dynamic xdata = ee.data;
                                     string message = xdata.message;

                                     //Console.WriteLine(new { message });

                                     if (message == "addFrame")
                                     {
                                         Console.WriteLine("addFrame");

                                         // http://stackoverflow.com/questions/8776751/web-worker-dealing-with-imagedata-working-with-firefox-but-not-chrome
                                         //byte[] data = xdata.data;
                                         Uint8ClampedArray data = xdata.data;
                                         //data[
                                         // { data = [object Uint8ClampedArray] } 
                                         //Console.WriteLine(new { data });

                                         encoder.addFrame(data, true);


                                     }

                                     if (message == "finish")
                                     {
                                         Console.WriteLine("finish");

                                         encoder.finish();

                                         var bytes = Encoding.ASCII.GetBytes(encoder.stream().getData());
                                         var src = "data:image/gif;base64," + Convert.ToBase64String(bytes);

                                         ee.ports.WithEach(port => port.postMessage(src));

                                     }
                                 };
                         }
                     );





                     foreach (var data in frames)
                     {

                         dynamic xdata = new object();

                         xdata.message = "addFrame";
                         xdata.data = data;

                         // Error	4	Cannot convert lambda expression to type 'ScriptCoreLib.JavaScript.DOM.MessagePort[]' because it is not a delegate type	X:\jsc.svn\examples\javascript\synergy\jsgif\jsgif\Application.cs	171	38	jsgif


                         w.postMessage(
                             (object)xdata,
                             (MessageEvent ee) =>
                             {
                                 // ?
                                 Console.WriteLine("addFrame done");
                             }
                         );
                     }

                     w.postMessage(
                        new { message = "finish" },
                        (MessageEvent ee) =>
                        {
                            Console.WriteLine("finish done");

                            var src = (string)ee.data;

                            Console.WriteLine(e.Elapsed);
                            new IHTMLImage { src = src }.AttachToDocument();

                            w.terminate();
                        }
                     );



                     //var bytes = Encoding.ASCII.GetBytes(encoder.stream().getData());
                     //var src = "data:image/gif;base64," + Convert.ToBase64String(bytes);


                     //new IHTMLImage { src = src }.AttachToDocument();
                 }
             );

            new IHTMLButton { innerText = "encode via GIFEncoderAsync. works!" }.AttachToDocument().WhenClicked(
                btn =>
                {
                    btn.disabled = true;
                    var e = new Stopwatch();
                    e.Start();

                    var w = new GIFEncoderAsync(
                        width: x,
                        height: y,
                        delay: 1000 / 10
                    );

                    //http://www.w3schools.com/tags/tryit.asp?filename=tryhtml5_meter

                    var innerText = btn.innerText;

                    btn.Clear();

                    dynamic meter = new IHTMLElement("meter").AttachTo(btn);

                    meter.max = frames.Count;
                    var value = 0;

                    foreach (var data in frames)
                    {
                        w.addFrame((Uint8ClampedArray)(object)data,
                            delegate
                            {
                                Console.WriteLine("addFrame done");

                                value++;

                                meter.value = value;
                            }
                        );
                    }

                    w.finish(
                        src =>
                        {
                            Console.WriteLine("finish done");


                            Console.WriteLine(e.Elapsed);
                            new IHTMLImage { src = src }.AttachToDocument();

                            btn.innerText = innerText;

                            btn.disabled = false;
                            btn.title = new { e.Elapsed }.ToString();

                        }
                    );


                }
            );


            new IHTMLButton { innerText = "encode via GIFEncoderWorker. crashes the system? why?" }.AttachToDocument().WhenClicked(
                async btn =>
                {
                    Console.WriteLine("encoding!");

                    btn.disabled = true;
                    var e = new Stopwatch();
                    e.Start();

                    var src = await new GIFEncoderWorker(
                          x,
                          y,
                           delay: 1000 / 10,
                          frames: frames,

                          AtFrame:
                            index =>
                            {
                                btn.innerText = new { index, frames.Count }.ToString();

                            }
                      );



                    Console.WriteLine("done!");
                    Console.WriteLine(e.Elapsed);

                    new IHTMLImage { src = src }.AttachToDocument();


                    btn.disabled = false;
                    btn.title = new { e.Elapsed }.ToString();

                }
            );

        }
    public GIFEncoderAsync(
        int width,
        int height,
        int delay = 1000 / 15,
        int repeat = 0
        )
    {
        var xscope = new { width, height, repeat, delay };

        Console.WriteLine("will share scope data: " + xscope);

        var w = new Worker(
            scope =>
            {
                var encoder = default(GIFEncoder);
                Console.WriteLine("waiting for scope data");

                scope.onmessage +=
                    ze =>
                    {
                        #region once
                        if (encoder != null)
                            return;
                        #endregion


                        Console.WriteLine("new encoder");

                        dynamic zscope = ze.data;

                        int zwidth = zscope.width;
                        int zheight = zscope.height;
                        int zrepeat = zscope.repeat;
                        int zdelay = zscope.delay;

                        Console.WriteLine("got scope data: " + new { zwidth, zheight, zrepeat, zdelay });

                        encoder = new GIFEncoder();
                        encoder.setSize(zwidth, zheight);
                        encoder.setRepeat(zrepeat); //auto-loop
                        encoder.setDelay(zdelay);
                        encoder.start();

                        scope.onmessage +=
                            ee =>
                            {
                                dynamic xdata = ee.data;
                                string message = xdata.message;

                                //Console.WriteLine(new { message });


                                #region addFrame
                                if (message == "addFrame")
                                {
                                    //Console.WriteLinke("addFrame");

                                    // http://stackoverflow.com/questions/8776751/web-worker-dealing-with-imagedata-working-with-firefox-but-not-chrome
                                    //byte[] data = xdata.data;
                                    Uint8ClampedArray data = xdata.data;
                                    //data[
                                    // { data = [object Uint8ClampedArray] } 
                                    //Console.WriteLine(new { data });

                                    encoder.addFrame(data, true);

                                    ee.ports.WithEach(port => port.postMessage("ok"));
                                }
                                #endregion

                                #region finish
                                if (message == "finish")
                                {
                                    Console.WriteLine("finish");

                                    encoder.finish();

                                    var bytes = Encoding.ASCII.GetBytes(encoder.stream().getData());
                                    var src = "data:image/gif;base64," + Convert.ToBase64String(bytes);

                                    ee.ports.WithEach(port => port.postMessage(src));

                                }
                                #endregion

                            };
                    };

            }
        );

        w.postMessage(xscope);

        #region addFrame
        this.addFrame =
            (data, yield) =>
            {

                dynamic xdata = new object();

                xdata.message = "addFrame";
                xdata.data = data;

                // Error	4	Cannot convert lambda expression to type 'ScriptCoreLib.JavaScript.DOM.MessagePort[]' because it is not a delegate type	X:\jsc.svn\examples\javascript\synergy\jsgif\jsgif\Application.cs	171	38	jsgif


                w.postMessage(
                    (object)xdata,
                    (MessageEvent ee) =>
                    {
                        //Console.WriteLine("addFrame done");

                        if (yield != null)
                            yield();
                    }
                );

            };
        #endregion

        #region finish
        this.finish =
            yield_src =>
            {
                w.postMessage(
                      new { message = "finish" },
                      (MessageEvent ee) =>
                      {
                          //Console.WriteLine("finish done");

                          var src = (string)ee.data;

                          //Console.WriteLine(e.Elapsed);
                          //new IHTMLImage { src = src }.AttachToDocument();

                          w.terminate();

                          yield_src(src);
                      }
                   );
            };
        #endregion

    }
    public GIFEncoderWorker(
        int width,
        int height,
        int delay = 1000 / 15,
        int repeat = 0,

        //object transparentColor = null,

        IEnumerable<byte[]> frames = null,

        Action<int> AtFrame = null
        )
    {
        // X:\jsc.svn\examples\javascript\async\test\TestScopeWithDelegate\TestScopeWithDelegate\Application.cs

        //MethodTargetObjectData: Array[2]
        //0: type$Wp_akjqSvXzyEjEqVpOKCvA._8gAABqSvXzyEjEqVpOKCvA
        //AtFrame: $ctor$.f

        Console.WriteLine("enter GIFEncoderWorker");
        var progress = (new Progress<int>(
             x =>
             {
                 Console.WriteLine("DOM Progress: " + new { x, Thread.CurrentThread.ManagedThreadId });

                 if (AtFrame != null)
                     AtFrame(x);
             }
          ) as IProgress<int>);


        this.Task = System.Threading.Tasks.Task.Factory.StartNew(
            //Tuple.Create(progress,
                    new
                    {
                        width,
                        height,
                        delay,
                        repeat,
                        //transparentColor, 
                        frames = frames.ToArray()
                    }
            //)
            ,
            x =>
            {
                Console.WriteLine("in GIFEncoderWorker");

                // https://sites.google.com/a/jsc-solutions.net/backlog/knowledge-base/2014/201405/20140526/stack

                var src = default(string);

                // is this killing the rewrite?
                //Action<int> yield = xx.Item1.Report;
                Action<int> yield = progress.Report;

                // wtf?

                //0200003f GIFEncoderWorker
                //script: error JSC1000: Method: <.ctor>b__1, Type: GIFEncoderWorker; emmiting failed : System.NullReferenceException: Object reference not set to an instance of an object.
                //   at jsc.IL2ScriptGenerator.OpCode_newobj(IdentWriter w, Prestatement p, ILInstruction i, ILFlowStackItem[] s) in x:\jsc.internal.svn\compiler\jsc\Languages\JavaScript\IL2ScriptGenerator.OpCodes.Newobj.cs:line 151

                yield(0);

                //var x = xx.Item2;
                var state = new
                {
                    x.width,
                    x.height,
                    x.delay,
                    //x.transparentColor, 
                    x.repeat,
                    x.frames.Length
                };

                // { state = { width = 640, height = 480, delay = 100, repeat = 0, Length = 16 } } 
                Console.WriteLine(new { state });

                var encoder = new GIFEncoder();
                encoder.setSize(x.width, x.height);
                encoder.setRepeat(x.repeat); //auto-loop
                encoder.setDelay(x.delay);
                //encoder.setTransparent(x.transparentColor);
                encoder.start();
                //#if OK

                x.frames.WithEachIndex(
                    (frame, index) =>
                    {
                        Console.WriteLine("addFrame " + new { index });


                        encoder.addFrame((Uint8ClampedArray)(object)frame, true);

                        yield(index);
                    }
                );
                //#endif

                Console.WriteLine("finish");

                encoder.finish();

                var bytes = Encoding.ASCII.GetBytes(encoder.stream().getData());

                src = "data:image/gif;base64," + Convert.ToBase64String(bytes);

                return src;
            }
        );
    }