Convert Image to base64 and vice versa in Unity - c#

i wanted to convert this image to Base64 in unity C#
But I am kind of lost, can someone help?
This is my code
using UnityEngine;
using System.Collections;
using System.IO;
using UnityEngine.UI;
using System.Collections.Generic;
using UnityEngine.Networking;
public class GetCam : MonoBehaviour
{
WebCamTexture webCam;
string your_path = "C:\\Users\\Jay\\Desktop";
public RawImage display;
public AspectRatioFitter fit;
public void Start()
{
webCam = new WebCamTexture();
webCam.Play();
if(WebCamTexture.devices.Length==0)
{
Debug.LogError("can not found any camera!");
return;
}
int index = -1;
for (int i = 0; i < WebCamTexture.devices.Length; i++)
{
if (WebCamTexture.devices[i].name.ToLower().Contains("your webcam name"))
{
Debug.LogError("WebCam Name:" + WebCamTexture.devices[i].name + " Webcam Index:" + i);
index = i;
}
}
}
public void Update()
{
float ratio = (float)webCam.width / (float)webCam.height;
fit.aspectRatio = ratio;
float ScaleY = webCam.videoVerticallyMirrored ? -1f : 1f;
display.rectTransform.localScale = new Vector3(1f, ScaleY, 1f);
int orient = -webCam.videoRotationAngle;
display.rectTransform.localEulerAngles = new Vector3(0, 0, orient);
}
public void callTakePhoto()
{
StartCoroutine(TakePhoto());
}
IEnumerator TakePhoto()
{
yield return new WaitForEndOfFrame();
Texture2D photo = new Texture2D(webCam.width, webCam.height);
photo.SetPixels(webCam.GetPixels());
photo.Apply();
//Encode to a PNG
byte[] bytes = photo.EncodeToPNG();
//Convert PNG to Base64
//Write out the PNG. Of course you have to substitute your_path for something sensible
File.WriteAllBytes(your_path + "\\photo.png", bytes);
//lol
}
public void callpostRequest()
{
StartCoroutine(postRequest("http://127.0.0.1:5000/"));
}
IEnumerator postRequest(string url)
{
WWWForm form = new WWWForm();
form.AddField("name","hi from unity client");
// form.AddField("nice","ok");
UnityWebRequest uwr = UnityWebRequest.Post(url, form);
yield return uwr.SendWebRequest();
StartCoroutine(getRequest("http://127.0.0.1:5000/"));
if (uwr.isNetworkError)
{
Debug.Log("Error While Sending: " + uwr.error);
}
else
{
Debug.Log("Received: " + uwr.downloadHandler.text);
}
}
IEnumerator getRequest(string uri)
{
UnityWebRequest uwr = UnityWebRequest.Get(uri);
yield return uwr.SendWebRequest();
if (uwr.isNetworkError)
{
Debug.Log("Error While Sending: " + uwr.error);
}
else
{
Debug.Log("Received: " + uwr.downloadHandler.text);
}
}
}
For now all it does is click picture and save it to desktop and then below is the code of UnityWebRequest class which sends a hi message to a flask server and receives back the same
What i want to do is convert image to base64 and send to flask server, can anyone help? thank you

In general you would simply do Convert.ToBase64String(byte[])
string base64String = Convert.ToBase64String(byteArray);
and accordingly Convert.FromBase64String(string)
byte[] byteArray = Convert.FromBase64String(base64String);
Why though?
Images are "big" binary data. Base64 blows each byte up into hexadecimal chars which adds a lot of overhead.
=> Why not rather send the binary data directly?
See MultiPartFormFileSection and use the overload public static Networking.UnityWebRequest Post(string uri, List<IMultipartFormSection> multipartFormSections);
like e.g.
IEnumerator Upload(byte[] fileContent)
{
var sections = new List<IMultiPartFormSection>();
// According to your servers needs
sections.Add(new MultiPartFormFileSection("files", fileContent, "photo.png", "image/png"));
using(UnityWebRequest www = UnityWebRequest.Post("http://127.0.0.1:5000/", sections))
{
yield return www.SendWebRequest();
if (www.result != UnityWebRequest.Result.Success)
{
Debug.Log(www.error);
}
else
{
Debug.Log("Form upload complete!");
// Get the server response
// NO NEED FOR A GET REQUESTS!
var serverResponse = www.downloadHandler.text;
Debug.Log(serverResponse);
}
}
}
and for the downloading accordingly use UnityWebRequestTexture.GetTexture like
using (var uwr = UnityWebRequestTexture.GetTexture("https://www.my-server.com/myimage.png"))
{
yield return uwr.SendWebRequest();
if (uwr.result != UnityWebRequest.Result.Success)
{
Debug.Log(uwr.error);
}
else
{
// Get downloaded texture
var texture = DownloadHandlerTexture.GetContent(uwr);
...
}
}

Related

Unity3D game freezes when sending an API request

I'm using an open-source game to write a script, that captures the screen frames in a collection and sends the collection to an API server.
Capturing works fine, but as soon as the API request fires, the game freezes for ~500ms. If I understand correctly, this request blocks the main thread.
I've tried to send the request in a different thread, but get some weird errors.
How can I send requests in a background, so it doesn't block the main thread?
Here's my code:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using UnityEngine.Networking;
using System.Threading.Tasks;
public class Recorder : MonoBehaviour
{
private float captureInterval = 1f / 24f;
private readonly List<string> frames = new();
async void Update()
{
if (Time.timeSinceLevelLoad >= captureInterval)
{
StartCoroutine(CaptureFrame());
captureInterval = Time.timeSinceLevelLoad + (1f / 24f);
if (frames.Count >= 120)
{
StartCoroutine(CommitFrames(frames));
frames.Clear();
}
}
}
IEnumerator CaptureFrame()
{
yield return new WaitForEndOfFrame();
Texture2D texture = ScreenCapture.CaptureScreenshotAsTexture();
byte[] jpg = texture.EncodeToJPG();
string base64 = Convert.ToBase64String(jpg);
frames.Add(base64);
Destroy(texture);
}
IEnumerator CommitFrames(List<string> framesData)
{
var payload = new CommitFramesData() { frames = framesData };
var www = CreateRequest("http://my-api.test/api/frames", RequestType.POST, payload);
yield return www.SendWebRequest();
www.Dispose();
}
private UnityWebRequest CreateRequest(string path, RequestType type = RequestType.GET, object data = null)
{
var request = new UnityWebRequest(path, type.ToString());
if (data != null)
{
var bodyRaw = Encoding.UTF8.GetBytes(JsonUtility.ToJson(data));
request.uploadHandler = new UploadHandlerRaw(bodyRaw);
}
request.downloadHandler = new DownloadHandlerBuffer();
request.SetRequestHeader("Content-Type", "application/json");
return request;
}
}
public enum RequestType
{
GET = 0,
POST = 1,
PUT = 2
}
[Serializable]
class CommitFramesData
{
public List<string> frames;
}

How to get an image from a url and set it to an object in Unity

I have a method to create objects from prefabs. The prefab consists of the texts "Title" and "Description", as well as the image "Image".
In the method below, I get the text for "Title", "Description" and the URL of the image for "Image".
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
using Newtonsoft.Json.Linq;
using System.Threading.Tasks;
using UnityEngine.Networking;
public class CreateMonumentButtons : MonoBehaviour
{
public RectTransform prefarb;
public RectTransform content;
private string City;
private string URL = DataHolders.URL;
async private void Awake()
{
City = DataHolders.City;
StartCoroutine(Get());
}
void InitializeItemView (GameObject viewGameObject, string TextTitle, string TextDescription, string URLImg)
{
TestItemView view = new TestItemView(viewGameObject.transform);
view.Title.text = TextTitle;
view.Description.text = TextDescription;
File fileData;
Texture2d txture;
(File.Exists(URLImg)) {
fileData = File.ReadAllBytes(URLImg); //read the bytes from the file at URLImg's destination
txture = new Texture2D(0,0);//makes the new texture
txture.LoadImage(fileData);//loads the image from the file
view.Img.sprite = Sprite.Create(txture, new Rect(0,0,200,200), new Vector2());
//set Img.sprite to a new sprite at 0,0 with the dimensions 200x200
}
}
public class TestItemView
{
public Text Title;
public Text Description;
// public Image Image;
public TestItemView (Transform rootView)
{
Title = rootView.Find("Title").GetComponent<Text>();
Description = rootView.Find("Description").GetComponent<Text>();
// Image = rootView.Find("Image").GetComponent<Image>();
}
}
private IEnumerator Get()
{
WWWForm formT = new WWWForm();
formT.AddField("City", City);
WWW wwwT = new WWW(URL + "get_monuments.php", formT);
yield return wwwT;
if (wwwT.error != null)
{
Debug.Log("Ошибка: " + wwwT.error);
yield break;
}
WWWForm formD = new WWWForm();
formD.AddField("City", City);
WWW wwwD = new WWW(URL + "get_description.php", formD);
yield return wwwD;
if (wwwD.error != null)
{
Debug.Log("Ошибка: " + wwwD.error);
yield break;
}
WWWForm formI = new WWWForm();
formI.AddField("City", City);
WWW wwwI = new WWW(URL + "get_img.php", formI);
yield return wwwI;
if (wwwI.error != null)
{
Debug.Log("Ошибка: " + wwwI.error);
yield break;
}
WWWForm formL = new WWWForm();
formL.AddField("City", City);
WWW wwwL = new WWW(URL + "get_lenLists.php", formL);
yield return wwwL;
if (wwwL.error != null)
{
Debug.Log("Ошибка: " + wwwL.error);
yield break;
}
DataHolders.listLen = int.Parse(wwwL.text);
DataHolders.listImg = wwwI.text;
DataHolders.listDescription = wwwD.text;
DataHolders.listMonuments = wwwT.text;
var ListTitls = JObject.Parse(DataHolders.listMonuments);
var ListDescriptions = JObject.Parse(DataHolders.listDescription);
var ListImgs = JObject.Parse(DataHolders.listImg);
for( int i = 0; i < DataHolders.listLen; i++ )
{
// Debug.Log(i.ToString());
var Title = (string) ListTitls[i.ToString()];
var Description = (string) ListDescriptions[i.ToString()];
var Img = (string) ListImgs[i.ToString()];
var instance = GameObject.Instantiate(prefarb.gameObject) as GameObject;
instance.transform.SetParent(content, false);
InitializeItemView(instance, Title, Description, Img);
}
}
}
I don't understand how can I get an image from an image url and set its value to "Image".
But I am a beginner, so it is desirable that you explain something in simple terms.
Unity Beginner has explained it easily in just 1.5 minutes to Load Image from WebLink or URL.
But here, they used WWW, which is obsolete, so use UnityWebRequest instead. Here are the changes you need to perform while changing from WWW to UnityWebRequest.
Image doesn't have an attribute of Text, and instead you should get the file, load the image to a texture and set the Image's sprite as the texture.
File fileData;
Texture2d txture;
if (File.Exists(URLImg)) {
fileData = File.ReadAllBytes(URLImg); //read the bytes from the file at URLImg's destination
txture = new Texture2D(0,0);//makes the new texture
txture.LoadImage(fileData);//loads the image from the file
view.Img.sprite = Sprite.Create(txture, new Rect(0,0,200,200), new Vector2());
//set Img.sprite to a new sprite at 0,0 with the dimensions 200x200
}
with view.Img.sprite as an image rather than "text" because it's not painting text and rather an image.
I made a simple plugin for this.
If someone is interested, check this repo

How to save image in Unity that I get from Firebase?

I connect to Firebase from Unity, and get simple image from it. But I want to know how can I save this image for example in Assets folder of unity project?
void Start()
{
FirebaseStorage storage = FirebaseStorage.DefaultInstance;
Firebase.Storage.StorageReference path_reference = storage.GetReference("background/1.jpg")
"SavetoAssets = storage.GetReference("background/1.jpg")" // something like that.
}
This post is almost what you need. I just expanded it with the FileIO part using FileStream.WriteAsync and used UnityWebRequestTexture instead of WWW:
private void Start()
{
FirebaseStorage storage = FirebaseStorage.DefaultInstance;
Firebase.Storage.StorageReference path_reference = storage.GetReference("background/1.jpg");
path_reference.GetValueAsync().ContinueWith(
task =>
{
Debug.Log("Default Instance entered");
if (task.IsFaulted)
{
Debug.Log("Error retrieving data from server");
}
else if (task.IsCompleted)
{
DataSnapshot snapshot = task.Result;
string data_URL = snapshot.GetValue(true).ToString();
//Start coroutine to download image
StartCoroutine(DownloadImage(data_URL));
}
}
);
}
private IEnumerator DownloadImage(string url)
{
using (UnityWebRequest uwr = UnityWebRequestTexture.GetTexture(url))
{
yield return uwr.SendWebRequest();
if (uwr.isNetworkError || uwr.isHttpError)
{
Debug.Log(uwr.error);
}
else
{
// Instead of accessing the texture
//var texture = DownloadHandlerTexture.GetContent(uwr);
// you can directly get the bytes
var bytes = DownloadHandlerTexture.GetData(uwr);
// and write them to File e.g. using
using (FileStream fileStream = File.Open(filename, FileMode.OpenOrCreate))
{
fileStream.WriteAsync(bytes, 0, bytes.Length);
}
}
}
}
Note: I don't use Firebase, Android nor iOs so I couldn't test this

You are using download over http. Currently Unity adds NSAllowsArbitraryLoads to Info.plist to simplify transition, but it will be removed soon [duplicate]

This question already has an answer here:
You are using download over http. Currently Unity adds NSAllowsArbitraryLoads to Info.plist to simplify transition
(1 answer)
Closed 4 years ago.
I am uploading data to database using WWW.
I have two data classes for data object.
[Serializable]
public class pushdatawrapper{
public string email;
public pushdata[] shotsArray=new pushdata[1];
}
[Serializable]
public class pushdata{
public string timehappened;
public string clubtype;
public pushdata(string timestamp_,string clubtype_)
{
timehappened = timestamp_;
clubtype = clubtype_;
}
}
Loading Json array of data object to database, I tried two approaches.
The first one was ok, but the second one is always failed at calling StartCoroutine function.
First approach
public class BLEBridge : MonoBehaviour {
void Start () {
pushdata_ pdata = new pushdata_("123123123123.0","15","123.0","123.0", "123.0", "123.0","123.0", "123.0","123.0","123.0","123.0","123.0", "First");
pushdatawrapper_ pw = new pushdatawrapper_ ();
pw.email = "test#gmail.com";
pw.shotsArray[0] = pdata;
StartCoroutine (PushData_ (pw));
}
private IEnumerator PushData_(pushdatawrapper_ pdata){
WWW www;
Hashtable postHeader = new Hashtable();
postHeader.Add("Content-Type", "application/json");
string dataToJason = JsonUtility.ToJson(pdata);
Debug.Log ("dataToJason " + dataToJason);
// convert json string to byte
var formData = System.Text.Encoding.UTF8.GetBytes(dataToJason);
www = new WWW("http://rmotion.rapsodo.com/api/push/new", formData, postHeader);
StartCoroutine(WaitForRequest(www));
return www;
}
IEnumerator WaitForRequest(WWW data)
{
yield return data; // Wait until the download is done
if (data.error != null)
{
Debug.Log("There was an error sending request: " + data.text);
}
else
{
Debug.Log("WWW Request: " + data.text);
}
}
}
This first method is always ok.
But in actual implementation, I need to upload data from a static function. Those private IEnumerator PushData_(pushdatawrapper_ pdata) and IEnumerator WaitForRequest(WWW data) can't be static.
So what I did was
I made a separate class as
public class UploadData: MonoBehaviour{
public void uploadindividualshot(pushdatawrapper pw){
StartCoroutine (PushData (pw));
}
private IEnumerator PushData(pushdatawrapper pdata){
WWW www;
Hashtable postHeader = new Hashtable();
postHeader.Add("Content-Type", "application/json");
string dataToJason = JsonUtility.ToJson(pdata);
Debug.Log ("dataToJason " + dataToJason);
// convert json string to byte
var formData = System.Text.Encoding.UTF8.GetBytes(dataToJason);
Debug.Log ("before www ");
www = new WWW("http://rmotion.rapsodo.com/api/push/new", formData, postHeader);
Debug.Log ("after new ");
StartCoroutine(WaitForRequest(www));
Debug.Log ("after WaitForRequest ");
return www;
}
IEnumerator WaitForRequest(WWW data)
{
Debug.Log ("start pushing ");
yield return data; // Wait until the download is done
if (data.error != null)
{
Debug.Log("There was an error sending request: " + data.text);
}
else
{
Debug.Log("WWW Request: " + data.text);
}
}
}
Then call the instance of the class from static method as
public class BLEBridge : MonoBehaviour {
void Start(){}
public unsafe static void GetGolfREsult()
{
pushdata pdata = new pushdata("123123123123.0","15","123.0","123.0", "123.0", "123.0","123.0", "123.0","123.0","123.0","123.0","123.0", "First");
pushdatawrapper pw = new pushdatawrapper();
pw.email = Login.loginName;
pw.shotsArray[0] = pdata;
UploadData up = new UploadData ();
up.uploadindividualshot (pw);
}
}
I always have error as
after new
UploadData:PushData(pushdatawrapper)
BLEBridge:GetGolfREsult()
(Filename: /Users/builduser/buildslave/unity/build/artifacts/generated/common/runtime/DebugBindings.gen.cpp Line: 51)
libc++abi.dylib: terminating with uncaught exception of type Il2CppExceptionWrapper
2018-04-29 17:25:25.565292+0800 RMotion[270:7241] You are using download over http. Currently Unity adds NSAllowsArbitraryLoads to Info.plist to simplify transition, but it will be removed soon. Please consider updating to https.
The program has error at StartCoroutine(WaitForRequest(www));
What is wrong with second approach?
In unity calling this line of code automatically start http request
WWW www = new WWW("url");
yield is just the convenience way to tell the coroutine to wait for the process to finish. Don't separate your calls in 2 IEnumerator.
private IEnumerator PushData_(pushdatawrapper_ pdata){
WWW www;
Hashtable postHeader = new Hashtable();
postHeader.Add("Content-Type", "application/json");
string dataToJason = JsonUtility.ToJson(pdata);
Debug.Log ("dataToJason " + dataToJason);
// convert json string to byte
var formData = System.Text.Encoding.UTF8.GetBytes(dataToJason);
www = new WWW("http://rmotion.rapsodo.com/api/push/new", formData, postHeader)
Debug.Log ("start pushing ");
yield return www; // Wait until the download is done
if (www.error != null)
{
Debug.Log("There was an error sending request: " + www.text);
}
else
{
Debug.Log("WWW Request: " + www.text);
}
}
And I don't see any use of pointer in your static method so why did you use the unsafe keyword?

Delay in accessing recently added data via Web Server [duplicate]

I am creating a HoloLens app using Unity which has to take data from a REST API and display it.
I am currently using WWW datatype to get the data and yield return statement in a coroutine that will be called from the Update() function. When I try to run the code, I get the latest data from the API but when someone pushes any new data onto the API, it does not automatically get the latest data in real time and I have to restart the app to see the latest data.
My Code:
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using System;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.IO;
public class TextChange : MonoBehaviour {
// Use this for initialization
WWW get;
public static string getreq;
Text text;
bool continueRequest = false;
void Start()
{
StartCoroutine(WaitForRequest());
text = GetComponent<Text>();
}
// Update is called once per frame
void Update()
{
}
private IEnumerator WaitForRequest()
{
if (continueRequest)
yield break;
continueRequest = true;
float requestFrequencyInSec = 5f; //Update after every 5 seconds
WaitForSeconds waitTime = new WaitForSeconds(requestFrequencyInSec);
while (continueRequest)
{
string url = "API Link goes Here";
WWW get = new WWW(url);
yield return get;
getreq = get.text;
//check for errors
if (get.error == null)
{
string json = #getreq;
List<MyJSC> data = JsonConvert.DeserializeObject<List<MyJSC>>(json);
int l = data.Count;
text.text = "Data: " + data[l - 1].content;
}
else
{
Debug.Log("Error!-> " + get.error);
}
yield return waitTime; //Wait for requestFrequencyInSec time
}
}
void stopRequest()
{
continueRequest = false;
}
}
public class MyJSC
{
public string _id;
public string author;
public string content;
public string _v;
public string date;
}
This is happening because resources caching is enabled on the Server.
Three possible solutions I know about:
1.Disable resources caching on the server. Instructions are different for every web server. Usually done in .htaccess.
2.Make each request with unique timestamp. The time should in Unix format.
This method will not work on iOS. You are fine since this is for HoloLens.
For example, if your url is http://url.com/file.rar, append ?t=currentTime at the end. currentTime is the actual time in Unix Format.
Full example url: http://url.com/file.rar?t=1468475141
Code:
string getUTCTime()
{
System.Int32 unixTimestamp = (System.Int32)(System.DateTime.UtcNow.Subtract(new System.DateTime(1970, 1, 1))).TotalSeconds;
return unixTimestamp.ToString();
}
private IEnumerator WaitForRequest()
{
string url = "API Link goes Here" + "?t=" + getUTCTime();
WWW get = new WWW(url);
yield return get;
getreq = get.text;
//check for errors
if (get.error == null)
{
string json = #getreq;
List<MyJSC> data = JsonConvert.DeserializeObject<List<MyJSC>>(json);
int l = data.Count;
text.text = "Data: " + data[l - 1].content;
}
else
{
Debug.Log("Error!-> " + get.error);
}
}
3.Disable Cache on the client side by supplying and modifying the Cache-Control and Pragma headers in the request.
Set Cache-Control header to max-age=0, no-cache, no-store then set Pragma header to no-cache.
I suggest you do this with UnityWebRequest instead of the WWW class. First, Include using UnityEngine.Networking;.
Code:
IEnumerator WaitForRequest(string url)
{
UnityWebRequest www = UnityWebRequest.Get(url);
www.SetRequestHeader("Cache-Control", "max-age=0, no-cache, no-store");
www.SetRequestHeader("Pragma", "no-cache");
yield return www.Send();
if (www.isError)
{
Debug.Log(www.error);
}
else
{
Debug.Log("Received " + www.downloadHandler.text);
}
}

Categories