繁体   English   中英

Unity3D - 将图像从PC内存上传到WebGL应用程序

[英]Unity3D - Upload a image from PC memory to WebGL app

我需要用户将他(她)的头像图片从PC上传到游戏

如何创建文件对话框并将图像上传到WebGL游戏?

今天是你的幸运日:PI接受了你的挑战。 这是你如何做到的。

首先是关于如何将JavaScript与Unity连接的说明。

读到我制作这个文件,我把它放在Assets/Plugins/WebGL/GetImage.jslib就像docs所说的那样

var getImage = {
    getImageFromBrowser: function(objectNamePtr, funcNamePtr) {
      // Because unity is currently bad at JavaScript we can't use standard
      // JavaScript idioms like closures so we have to use global variables :(
      window.becauseUnitysBadWithJavacript_getImageFromBrowser =
          window.becauseUnitysBadWithJavacript_getImageFromBrowser || {
         busy: false,
         initialized: false,
         rootDisplayStyle: null,  // style to make root element visible
         root_: null,             // root element of form
         ctx_: null,              // canvas for getting image data;
      };
      var g = window.becauseUnitysBadWithJavacript_getImageFromBrowser;
      if (g.busy) {
          // Don't let multiple requests come in
          return;
      }
      g.busy = true;

      var objectName = Pointer_stringify(objectNamePtr);
      var funcName = Pointer_stringify(funcNamePtr);

      if (!g.initialized) {
          g.initialized = true;
          g.ctx = window.document.createElement("canvas").getContext("2d");

          // Append a form to the page (more self contained than editing the HTML?)
          g.root = window.document.createElement("div");
          g.root.innerHTML = [
            '<style>                                                    ',
            '.getimage {                                                ',
            '    position: absolute;                                    ',
            '    left: 0;                                               ',
            '    top: 0;                                                ',
            '    width: 100%;                                           ',
            '    height: 100%;                                          ',
            '    display: -webkit-flex;                                 ',
            '    display: flex;                                         ',
            '    -webkit-flex-flow: column;                             ',
            '    flex-flow: column;                                     ',
            '    -webkit-justify-content: center;                       ',
            '    -webkit-align-content: center;                         ',
            '    -webkit-align-items: center;                           ',
            '                                                           ',
            '    justify-content: center;                               ',
            '    align-content: center;                                 ',
            '    align-items: center;                                   ',
            '                                                           ',
            '    z-index: 2;                                            ',
            '    color: white;                                          ',
            '    background-color: rgba(0,0,0,0.8);                     ',
            '    font: sans-serif;                                      ',
            '    font-size: x-large;                                    ',
            '}                                                          ',
            '.getimage a,                                               ',
            '.getimage label {                                          ',
            '   font-size: x-large;                                     ',
            '   background-color: #666;                                 ',
            '   border-radius: 0.5em;                                   ',
            '   border: 1px solid black;                                ',
            '   padding: 0.5em;                                         ',
            '   margin: 0.25em;                                         ',
            '   outline: none;                                          ',
            '   display: inline-block;                                  ',
            '}                                                          ',
            '.getimage input {                                          ',
            '    display: none;                                         ',
            '}                                                          ',
            '</style>                                                   ',
            '<div class="getimage">                                     ',
            '    <div>                                                  ',
            '      <label for="photo">click to choose an image</label>  ',
            '      <input id="photo" type="file" accept="image/*"/><br/>',
            '      <a>cancel</a>                                        ',
            '    </div>                                                 ',
            '</div>                                                     ',
          ].join('\n');
          var input = g.root.querySelector("input");
          input.addEventListener('change', getPic);

          // prevent clicking in input or label from canceling
          input.addEventListener('click', preventOtherClicks);
          var label = g.root.querySelector("label");
          label.addEventListener('click', preventOtherClicks);

          // clicking cancel or outside cancels
          var cancel = g.root.querySelector("a");  // there's only one
          cancel.addEventListener('click', handleCancel);
          var getImage = g.root.querySelector(".getimage");
          getImage.addEventListener('click', handleCancel);

          // remember the original style
          g.rootDisplayStyle = g.root.style.display;

          window.document.body.appendChild(g.root);
      }

      // make it visible
      g.root.style.display = g.rootDisplayStyle;

      function preventOtherClicks(evt) {
          evt.stopPropagation();
      }

      function getPic(evt) {
          evt.stopPropagation();
          var fileInput = evt.target.files;
          if (!fileInput || !fileInput.length) {
              return sendError("no image selected");
          }

          var picURL = window.URL.createObjectURL(fileInput[0]);
          var img = new window.Image();
          img.addEventListener('load', handleImageLoad);
          img.addEventListener('error', handleImageError);
          img.src = picURL;
      }

      function handleCancel(evt) {
          evt.stopPropagation();
          evt.preventDefault();
          sendError("cancelled");
      }

      function handleImageError(evt) {
          sendError("Could not get image");
      }

      function handleImageLoad(evt) {
          var img = evt.target;
          window.URL.revokeObjectURL(img.src);
          // We probably don't want the fullsize image. It might be 3000x2000 pixels or something too big
          g.ctx.canvas.width  = 256;
          g.ctx.canvas.height = 256;
          g.ctx.drawImage(img, 0, 0, g.ctx.canvas.width, g.ctx.canvas.height);

          var dataUrl = g.ctx.canvas.toDataURL();

          // free the canvas memory (could probably be zero)
          g.ctx.canvas.width  = 1;
          g.ctx.canvas.height = 1;

          sendResult(dataUrl);
          g.busy = false;
      }

      function sendError(msg) {
          sendResult("error: " + msg);
      }

      function hide() {
          g.root.style.display = "none";
      }

      function sendResult(result) {
          hide();
          g.busy = false;
          SendMessage(objectName, funcName, result);
      }
    },
};

mergeInto(LibraryManager.library, getImage);

该代码遵循此示例,说明如何从HTML5中的用户获取图像

基本上它是一个覆盖整个浏览器窗口的小表单。 它有一个只接受图像的<input>元素。 它附加了文档正文,如果你要求另一张图像,它会再次使用它。 (参见g.initializedg.root

同样地,尝试一次只能调用一次。 (见g.busy

一旦用户选择了图像,图像就被绘制成一个较小的画布,因为我只是猜测你真的不想要3000x2000像素图像或用户照片的任何巨大尺寸。

您可能需要调整用于调整画布大小并绘制图像的代码。 当前代码始终将图像大小调整为256x256

          g.ctx.canvas.width  = 256;
          g.ctx.canvas.height = 256;
          g.ctx.drawImage(img, 0, 0, g.ctx.canvas.width, g.ctx.canvas.height);

例如,您可能希望将画布大小设置为与原始图像相同的宽高比,但仍然需要更小的尺寸。 或者,如果您想要原始大小,则将大小设置为img.widthimg.height

在任何情况下,在将图像绘制到画布之后,我们调用canvas.toDataURL ,它返回编码为字符串dataURL的PNG。 然后,它使用Unity的SendMessage函数调用命名的GameObject上的命名方法,并传递dataURL。

为了将该代码与Unity接口,我创建了这个文件Assets/GetImage.cs

using UnityEngine;
using System.Collections;
using System.Runtime.InteropServices;

public class GetImage {

    #if UNITY_WEBGL

        [DllImport("__Internal")]
        private static extern void getImageFromBrowser(string objectName, string callbackFuncName);

    #endif

    static public void GetImageFromUserAsync(string objectName, string callbackFuncName)
    {
        #if UNITY_WEBGL

            getImageFromBrowser(objectName, callbackFuncName);

        #else

            Debug.LogError("Not implemented in this platform");

        #endif
    }
}

此代码的工作方式使用您调用GetImage.GetImageFromBrowserAsync 您传递GameObject的名称和要调用的方法的名称。 GameObject的名称必须是唯一的 (好吧,如果它不是唯一的Unity将尝试在具有相同名称的每个对象上调用该方法)

该方法将使用字符串调用。 如果该字符串以data:image/png;base64,开头data:image/png;base64,则用户选择图像。 我们将其转换回二进制PNG数据,然后调用Texture2D.LoadImage

如果字符串不是以data:image/png;base64,开头data:image/png;base64,则表示错误。 也许用户选择取消?

注意:代码当前不处理所有错误。

为了使用它,我制作了一个Cube GameObject,添加了一个材料,然后我添加了一个新脚本Assets/ClickAndGetImage.cs

using UnityEngine;
using System;
using System.Collections;

public class ClickAndGetImage : MonoBehaviour {

    void OnMouseOver()
    {
        if(Input.GetMouseButtonDown(0))
        {
            // NOTE: gameObject.name MUST BE UNIQUE!!!!
            GetImage.GetImageFromUserAsync(gameObject.name, "ReceiveImage");
        }
    }

    static string s_dataUrlPrefix = "data:image/png;base64,";
    public void ReceiveImage(string dataUrl)
    {
        if (dataUrl.StartsWith(s_dataUrlPrefix))
        {
            byte[] pngData = System.Convert.FromBase64String(dataUrl.Substring(s_dataUrlPrefix.Length));

            // Create a new Texture (or use some old one?)
            Texture2D tex = new Texture2D(1, 1); // does the size matter?
            if (tex.LoadImage(pngData))
            {
                Renderer renderer = GetComponent<Renderer>();

                renderer.material.mainTexture = tex;
            }
            else
            {
                Debug.LogError("could not decode image");
            }
        }
        else
        {
            Debug.LogError("Error getting image:" + dataUrl);
        }
    }
}

例

你可以在这里看到它

代码在github上

这是一个.unitypackage

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM