Search Unity

WebGL - Screenshot

Discussion in 'Web' started by Forseti1, Jul 3, 2019.

  1. Forseti1

    Forseti1

    Joined:
    Mar 3, 2018
    Posts:
    8
    I'm using Unity 5.6.4 and I've got a game where you've got to find a bunch of stuff and when you find them all you go to a scene where there's confetti raining down and it says "you took xx:xx:xx" I want a button at the bottom where you click and it save a screenshot of the time taken. the game will be on a site and as an .exe. I've got the screenshot for the .exe version done and working its the downloading from webGL that isn't working. I know I need a .jslib to have the download function and then call that from the unity script.

    In Assets/Plugins I've got download.jslib
    Code (JavaScript):
    1. mergeInto(LibraryManager.library, {
    2.   Download: function (data, filename, type) {
    3.     var file = new Blob([data], {type: type});
    4.     if (window.navigator.msSaveOrOpenBlob) // IE10+
    5.         window.navigator.msSaveOrOpenBlob(file, filename);
    6.     else { // Others
    7.         var a = document.createElement("a"),
    8.                 url = URL.createObjectURL(file);
    9.         a.href = url;
    10.         a.download = filename;
    11.         document.body.appendChild(a);
    12.         a.click();
    13.         setTimeout(function() {
    14.             document.body.removeChild(a);
    15.             window.URL.revokeObjectURL(url);
    16.         }, 0);
    17.     }
    18.   }
    19.  
    20. });
    This is called in the unity file save_Screenshot.cs

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using System.Runtime.InteropServices;
    4. using UnityEngine;
    5.  
    6. public class Save_Screenshot : MonoBehaviour {
    7.  
    8.     [DllImport("__Internal")]
    9.     private static extern void Download(byte[] data, string filename, string type);
    10.  
    11.     private static Save_Screenshot instance;
    12.  
    13.     private Camera myCamera;
    14.     private bool takeScreenshot = false;
    15.  
    16.     private void Awake () {
    17.         instance = this;
    18.         myCamera = gameObject.GetComponent<Camera> ();
    19.     }
    20.  
    21.     private void TakeScreenshot(int width, int height){
    22.         myCamera.targetTexture = RenderTexture.GetTemporary (width, height, 16);
    23.         takeScreenshot = true;
    24.     }
    25.  
    26.     IEnumerator OnPostRender() {
    27.         if (takeScreenshot) {
    28.             yield return new WaitForEndOfFrame ();
    29.             takeScreenshot = false;
    30.             RenderTexture renderTexture = myCamera.targetTexture;
    31.  
    32.             Texture2D renderResult = new Texture2D (renderTexture.width, renderTexture.height, TextureFormat.ARGB32, false);
    33.             Rect rect = new Rect (0, 0, renderTexture.width, renderTexture.height);
    34.             renderResult.ReadPixels (rect, 0, 0);
    35.  
    36.             byte[] byteArray = renderResult.EncodeToPNG ();
    37.             Download (byteArray, "Time Taken.png", "image/png");
    38.  
    39.             RenderTexture.ReleaseTemporary (renderTexture);
    40.             myCamera.targetTexture = null;
    41.         }
    42.     }
    43.  
    44.     public static void staticScreenshot(int width, int height){
    45.         instance.TakeScreenshot (width, height);
    46.     }
    47. }
    When i run this in editor to test it I get an error


    EntryPointNotFoundException: Download
    Save_Screenshot+<OnPostRender>c__Iterator0.MoveNext () (at Assets/Scripts/Save_Screenshot.cs:38)
    UnityEngine.SetupCoroutine.InvokeMoveNext (IEnumerator enumerator, IntPtr returnValueAddress) (at C:/buildslave/unity/build/Runtime/Export/Coroutines.cs:17)


    Thinking this may be because I'm trying to do it in editor not on a browser I tried to build it but I got a error saying its failed its sanity check

    LSupport\\BuildTools\\emscripten.config_sanity'
    stderr:WARNING:root:did not see a source tree above or next to the LLVM root directory (guessing based on directory of C:\Program Files\Unity\Editor\Data\PlaybackEngines\WebGLSupport\BuildTools\Emscripten_FastComp_Win\llc), could not verify version numbers match
    INFO:root:(Emscripten: Running sanity checks)
    WARNING:root:java does not seem to exist, required for closure compiler, which is optional (define JAVA in C:\Program Files\Unity\Editor\Data\PlaybackEngines\WebGLSupport\BuildTools\emscripten.config if you want it)
    WARNING:root:closure compiler will not be available
    WARNING:root:--separate-asm works best when compiling to HTML. otherwise, you must yourself load the '.asm.js' file that is emitted separately, and must do so before loading the main '.js` file
    error: failure to execute js library "L:\unity\Test\Assets\Plugins\test.jslib": SyntaxError: Unexpected token ILLEGAL,,SyntaxError: Unexpected token ILLEGAL at Object.LibraryManager.load (eval at globalEval (C:\Program Files\Unity\Editor\Data\PlaybackEngines\WebGLSupport\BuildTools\Emscripten\src\compiler.js:105:8), <anonymous>:173:14) at JSify (eval at globalEval (C:\Program Files\Unity\Editor\Data\PlaybackEngines\WebGLSupport\BuildTools\Emscripten\src\compiler.js:105:8), <anonymous>:59:20) at L:\unity\Test\Assets\Plugins\test.jslib (C:\Program Files\Unity\Editor\Data\PlaybackEngines\WebGLSupport\BuildTools\Emscripten\src\compiler.js:208:3) at Module._compile (module.js:460:26) at Object.Module._extensions..js (module.js:478:10) at Module.load (module.js:355:32) at Function.Module._load (module.js:310:12) at Function.Module.runMain (module.js:501:10) at startup (node.js:129:16) at node.js:814:3preprocessed source (you can run a js engine on this to get a clearer error message sometimes):=============��m
    UnityEditor.HostView:OnGUI()

    And another error

    L/Extensions/Unity.WebGL.extensions/BuildPostprocessor.cs:437)
    UnityEditor.WebGL.WebGlBuildPostprocessor.PostProcess (BuildPostProcessArgs args) (at /Users/builduser/buildslave/unity/build/PlatformDependent/WebGL/Extensions/Unity.WebGL.extensions/BuildPostprocessor.cs:877)
    UnityEditor.PostprocessBuildPlayer.Postprocess (BuildTargetGroup targetGroup, BuildTarget target, System.String installPath, System.String companyName, System.String productName, Int32 width, Int32 height, System.String downloadWebplayerUrl, System.String manualDownloadWebplayerUrl, BuildOptions options, UnityEditor.RuntimeClassRegistry usedClassRegistry, UnityEditor.BuildReporting.BuildReport report) (at C:/buildslave/unity/build/Editor/Mono/BuildPipeline/PostprocessBuildPlayer.cs:186)
    UnityEditor.HostView:OnGUI()


    Any idea what I'm doing wrong?
     
  2. sumpfkraut

    sumpfkraut

    Joined:
    Jan 18, 2013
    Posts:
    242
    It seems you'r JS code have a error. But i can't say where.

    here is what i use to download a file:
    Code (CSharp):
    1. [DllImport("__Internal")]
    2. private static extern void DownloadFile(byte[] array, int byteLength, string fileName);
    3.  
    4. //....
    5. byte[] imageData = screenShot.EncodeToJPG(); //screenShot is Texture2D
    6. string customFileName = "MyScreenshot.jpg";
    7. DownloadFile(imageData, imageData.Length, customFileName);
    My Jslib:
    Code (JavaScript):
    1. var DownloadFilePlugin = {
    2.   DownloadFile : function(array, size, fileNamePtr)
    3.   {
    4.     var fileName = UTF8ToString(fileNamePtr);
    5.     var bytes = new Uint8Array(size);
    6.     for (var i = 0; i < size; i++)
    7.     {
    8.        bytes[i] = HEAPU8[array + i];
    9.     }
    10.     var blob = new Blob([bytes]);
    11.     var link = document.createElement('a');
    12.     link.href = window.URL.createObjectURL(blob);
    13.     link.download = fileName;
    14.     var event = document.createEvent("MouseEvents");
    15.     event.initMouseEvent("click");
    16.     link.dispatchEvent(event);
    17.     window.URL.revokeObjectURL(link.href);
    18.   }
    19. };
    20. mergeInto(LibraryManager.library, DownloadFilePlugin);
     
    Last edited: Jul 4, 2019
    Graham-B likes this.
  3. Forseti1

    Forseti1

    Joined:
    Mar 3, 2018
    Posts:
    8
    Used your code and got slightly different error

    Failed running "C:\Program Files\Unity\Editor\Data\PlaybackEngines\WebGLSupport\BuildTools\Emscripten_Win\python\2.7.5.3_64bit\python.exe" "C:\Program Files\Unity\Editor\Data\PlaybackEngines\WebGLSupport\BuildTools\Emscripten\emcc" @"L:\unity\Test\Assets\..\Temp\emcc_arguments.resp"

    stdout:WARNING: sanity check failed to run [Errno 13] Permission denied: 'C:\\Program Files\\Unity\\Editor\\Data\\PlaybackEngines\\WebGLSupport\\BuildTools\\emscripten.config_sanity'
    stderr:WARNING:root:did not see a source tree above or next to the LLVM root directory (guessing based on directory of C:\Program Files\Unity\Editor\Data\PlaybackEngines\WebGLSupport\BuildTools\Emscripten_FastComp_Win\llc), could not verify version numbers match
    INFO:root: (Emscripten: Running sanity checks)
    WARNING:root:java does not seem to exist, required for closure compiler, which is optional (define JAVA in C:\Program Files\Unity\Editor\Data\PlaybackEngines\WebGLSupport\BuildTools\emscripten.config if you want it)
    WARNING:root:closure compiler will not be available
    WARNING:root:--separate-asm works best when compiling to HTML. otherwise, you must yourself load the '.asm.js' file that is emitted separately, and must do so before loading the main '.js` file
    error: failure to execute js library "L:\unity\Test\Assets\Plugins\download.jslib": SyntaxError: Unexpected token ILLEGAL,,SyntaxError: Unexpected token ILLEGAL at Object.LibraryManager.load (eval at globalEval (C:\Program Files\Unity\Editor\Data\PlaybackEngines\WebGLSupport\BuildTools\Emscripten\src\compiler.js:105:8), <anonymous>:173:14) at JSify (eval at globalEval (C:\Program Files\Unity\Editor\Data\PlaybackEngines\WebGLSupport\BuildTools\Emscripten\src\compiler.js:105:8), <anonymous>:59:20) at L:\unity\Test\Assets\Plugins\download.jslib (C:\Program Files\Unity\Editor\Data\PlaybackEngines\WebGLSupport\BuildTools\Emscripten\src\compiler.js:208:3) at Module._compile (module.js:460:26) at Object.Module._extensions..js (module.js:478:10) at Module.load (module.js:355:32) at Function.Module._load (module.js:310:12) at Function.Module.runMain (module.js:501:10) at startup (node.js:129:16) at node.js:814:3preprocessed source (you can run a js engine on this to get a clearer error message sometimes):=============��v
    UnityEditor.BuildPlayerWindow:BuildPlayerAndRun()

    and

    Exception: Failed building WebGL Player.
    UnityEditor.WebGL.ProgramUtils.StartProgramChecked (System.Diagnostics.ProcessStartInfo p) (at /Users/builduser/buildslave/unity/build/PlatformDependent/WebGL/Extensions/Unity.WebGL.extensions/ProgramUtils.cs:48)
    UnityEditor.WebGL.WebGlBuildPostprocessor.EmscriptenLink (BuildPostProcessArgs args, Boolean wasmBuild, System.String sourceFiles, System.String sourceFilesHash) (at /Users/builduser/buildslave/unity/build/PlatformDependent/WebGL/Extensions/Unity.WebGL.extensions/BuildPostprocessor.cs:394)
    UnityEditor.WebGL.WebGlBuildPostprocessor.LinkBuild (BuildPostProcessArgs args) (at /Users/builduser/buildslave/unity/build/PlatformDependent/WebGL/Extensions/Unity.WebGL.extensions/BuildPostprocessor.cs:437)
    UnityEditor.WebGL.WebGlBuildPostprocessor.PostProcess (BuildPostProcessArgs args) (at /Users/builduser/buildslave/unity/build/PlatformDependent/WebGL/Extensions/Unity.WebGL.extensions/BuildPostprocessor.cs:877)
    UnityEditor.PostprocessBuildPlayer.Postprocess (BuildTargetGroup targetGroup, BuildTarget target, System.String installPath, System.String companyName, System.String productName, Int32 width, Int32 height, System.String downloadWebplayerUrl, System.String manualDownloadWebplayerUrl, BuildOptions options, UnityEditor.RuntimeClassRegistry usedClassRegistry, UnityEditor.BuildReporting.BuildReport report) (at C:/buildslave/unity/build/Editor/Mono/BuildPipeline/PostprocessBuildPlayer.cs:186)
    UnityEditor.BuildPlayerWindow:BuildPlayerAndRun()
     
    Last edited: Jul 4, 2019
  4. sumpfkraut

    sumpfkraut

    Joined:
    Jan 18, 2013
    Posts:
    242
    Last edited: Jul 4, 2019
  5. Forseti1

    Forseti1

    Joined:
    Mar 3, 2018
    Posts:
    8
    That's the only the only plugin in there, and I've checked all the other assets and only one has a plugins folder, and that contains a .cs that doesn't have an option to disable it for certain versions like that link said. I made another project just with that .jslib and script and it did manage to build, so there must be something I'm missing, but when I tried to use it, it threw an error saying I needed emscripten's linking support to use dlopen. But when I looked at https://docs.unity3d.com/560/Documentation/Manual/webgl-gettingstarted.html it says that Unity already uses emscripten, or is this some different part of it i need to download?
     
  6. JJJohan

    JJJohan

    Joined:
    Mar 18, 2016
    Posts:
    214
    It sounds like you have one or more rogue characters in your script that's breaking the JavaScript parser.

    error: failure to execute js library "L:\unity\Test\Assets\Plugins\download.jslib": SyntaxError: Unexpected token ILLEGAL

    I don't see any weird characters in the script block above from a quick glance but you might have some characters before or after the code - just double check you copy-pasted it correctly.

    Some tips for finding it:
    https://stackoverflow.com/a/12719860
     
  7. Forseti1

    Forseti1

    Joined:
    Mar 3, 2018
    Posts:
    8
    I put the code in codepen.io and it didn't find any invisible characters.
     
  8. sumpfkraut

    sumpfkraut

    Joined:
    Jan 18, 2013
    Posts:
    242
    I tested your code, and i can build the app without any problems.
    using Unity2019.1.5.f1
     
  9. Forseti1

    Forseti1

    Joined:
    Mar 3, 2018
    Posts:
    8
    I've got Unity 5.6.4 the problem could be that I'm just using an old version of Unity. I think I will just have to try talk work into getting Unity 2019
     
  10. Krieger56

    Krieger56

    Joined:
    Jul 25, 2019
    Posts:
    1
    WebGL (Web Graphics Library) is a JavaScript API for rendering interactive 3D and 2D graphics within any compatible web browser without the use of plug-ins.WebGL does so by introducing an API that closely conforms to OpenGL ES 2.0 that can be used in HTML5 <canvas> elements tutuapp software.
     
    Last edited: Jul 26, 2019
  11. Graham-B

    Graham-B

    Joined:
    Feb 27, 2013
    Posts:
    331
    This works like a charm in Chrome and Firefox! Thanks for sharing.

    The only problem is, Edge throws the exception "TypeError: Argument not optional"

    Anyone know why this could be?
     
  12. Tushar_kmphasis

    Tushar_kmphasis

    Joined:
    Oct 5, 2019
    Posts:
    7
    1. var DownloadFilePlugin = {
    2. DownloadFile : function(array, size, fileNamePtr)
    3. {
    4. var fileName = UTF8ToString(fileNamePtr);
    5. var bytes = new Uint8Array(size);
    6. for (var i = 0; i < size; i++)
    7. {
    8. bytes = HEAPU8[array + i];
      [*] }
      [*] var blob = new Blob([bytes]);
      [*] var link = document.createElement('a');
      [*] link.href = window.URL.createObjectURL(blob);
      [*] link.download = fileName;
      [*] var event = document.createEvent("MouseEvents");
      [*] event.initMouseEvent("click");
      [*] link.dispatchEvent(event);
      [*] window.URL.revokeObjectURL(link.href);
      [*] }
      [*]};
      [*]mergeInto(LibraryManager.library, DownloadFilePlugin);




    this is perfectly work for chrome and safari.
    but there is an error with Microsoft edge anyone has a solution??
     
  13. JJJohan

    JJJohan

    Joined:
    Mar 18, 2016
    Posts:
    214
    You might have a bit of luck replacing it with this to account for Edge - hopefully works for all browsers:
    Code (JavaScript):
    1. var DownloadFilePlugin = {
    2.   DownloadFile : function(array, size, fileNamePtr)
    3.   {
    4.     var fileName = UTF8ToString(fileNamePtr);
    5.     var bytes = new Uint8Array(size);
    6.     for (var i = 0; i < size; i++)
    7.     {
    8.        bytes[i] = HEAPU8[array + i];
    9.     }
    10.     var blob = new Blob([bytes]);
    11.     var link = document.createElement('a');
    12.     link.href = window.URL.createObjectURL(blob);
    13.     link.download = fileName;
    14.     link.dispatchEvent(new MouseEvent('click', {bubbles: true, cancelable: true, view: window}));
    15.     window.URL.revokeObjectURL(link.href);
    16.   }
    17. };
    18. mergeInto(LibraryManager.library, DownloadFilePlugin);
     
    Graham-B likes this.
  14. crafTDev

    crafTDev

    Joined:
    Nov 5, 2008
    Posts:
    1,820
    Hello,

    I tested this but it doesn't download an actual png, its a file without an extension and when you open it in Text Editor it just has a number. Is there anything else I am missing?

    Edit:Tried the one above and it works. One issue I have now though is I am using Device camera and it only takes picture of UI shown and not the environment actual view of device camera.
     
    Last edited: Apr 25, 2021
  15. MindGem

    MindGem

    Joined:
    May 11, 2017
    Posts:
    84
    Hello everyone. I've tried this code and browsed endless of forum posts and tutorials wihtout success of making a "Save Screenshot" function for my webgl game. If anyone would be interested in helping me personally getting this done I have $100 bucks to Paypal over to you as payment for the job.

    My webgl game can be found here: https://www.graffiticreator.net
    I also have a save function that works perfectly inside the editor and on desktop but of course not for webgl so maybe there's not so much work to do.

    Please let me know.
     
  16. sumpfkraut

    sumpfkraut

    Joined:
    Jan 18, 2013
    Posts:
    242
    DhiaSendi likes this.