Unity3D - 从PC内存WebGL的应用程序上传图像 [英] Unity3D - Upload a image from PC memory to WebGL app

查看:1924
本文介绍了Unity3D - 从PC内存WebGL的应用程序上传图像的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I need user to upload his(her) avatar picture from PC to game

如何创建一个文件对话框,并上传到WebGL的游戏形象?

How can I create a file dialog and upload a image to WebGL game?

推荐答案

今天是你的幸运日:PI拿起你的挑战。这里是你如何做到这一点。

Today is your lucky day :P I took up your challenge. Here's how you do it.

首先上的如何JavaScript的接口使用Unity是这里

阅读,我把这个文件,我放在资产/Plugins/WebGL/GetImage.jslib 如文档说

Reading that I made this file which I put in Assets/Plugins/WebGL/GetImage.jslib like the docs said

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 用户获得的图像这个例子。

The code follows this example of how to get an image from a user in HTML5.

基本上,它使一个小的,覆盖了整个浏览器窗口。它有一个<输入> 元素只接受的图像。它是附加在做文档的身体,如果你问其他图像会再次使用它。 (见 g.initialized g.root

Basically it makes a small form that covers the entire browser window. It has an <input> element that only accepts an image. It appends that do the body of the document and will use it again if you ask for another image. (see g.initialized and g.root)

同样有一个尝试,你只能在一个时间调用它一次。 (见 g.busy

Similarly there's an attempt that you can only call it once at a time. (see g.busy)

一旦用户选择了一个图像,然后将图像绘制成的小画布,因为我只是猜测,你真的不想要一个3000x2000汽车像素的图像或其他巨型大小用户的照片是

Once the user chooses an image the image is then drawn into a smaller canvas because I'm just guessing that you don't really want a 3000x2000 pixel image or whatever giant size the user's photo is.

您可能需要调整大小的的代码帆布绘制图像。目前的代码总是调整图像大小256×256到

You may want to adjust the code that sizes the canvas and draws the image. The current code always resizes the image to 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.width img.height

For example you might want to set the canvas size to be the same aspect ratio as the original image but still some smaller size. Or, if you want the original size then set the size to img.width and img.height.

在任何情况下,在图像绘制到返回编码成一个字符串PNG我们称之为画布 canvas.toDataURL dataURL。然后,它调用使用统一的 SendMessage函数函数命名游戏物体命名方法,并将dataURL。

In any case, after the image is drawn into the canvas we call canvas.toDataURL which returns a PNG encoded into a string dataURL. It then calls a named method on a named GameObject using Unity's SendMessage function and passes the dataURL.

要的界面,使用Unity的代码我做了这个文件资产/ GetImage.cs

To interface that code with Unity I made this file 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 。你通过它的游戏对象的名称和调用方法的名称。游戏对象的的名称必须是唯一(当然,如果它不是唯一的统一将尝试调用每一个对象的方法具有相同的名称)

The way this code works use you call GetImage.GetImageFromBrowserAsync. You pass it the name of a GameObject and the name of a method to call. The name of the GameObject MUST BE UNIQUE (well, if it's not unique Unity will attempt to call the method on every object with the same name)

的方法,将与字符串被调用。如果字符串数据开始:图像/ PNG; BASE64,然后用户选择的图像。我们将其转换为二进制PNG数据,然后调用 Texture2D.LoadImage

The method will be called with a string. If that string starts with data:image/png;base64, then the user chose an image. We convert that back to binary PNG data and then call Texture2D.LoadImage

如果字符串不以<启动code>数据:图像/ PNG; BASE64,那么它是一个错误。 ?也许用户选取取消

If the string does not start with data:image/png;base64, then it's an error. Maybe the user picked cancel?

注:代码不处理所有的错误目前

Note: The code doesn't handle all errors currently.

要使用它我做了一个魔方游戏物体,补充材料,然后我添加了一个新的脚本资产/ ClickAndGetImage.cs

To use it I made a Cube GameObject, added a material, then I added a new script 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

这篇关于Unity3D - 从PC内存WebGL的应用程序上传图像的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆