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; } ); }