How can I convert UnityEngine.Object[] that contains Texture2D to Texture2D[] - c#

How can I convert UnityEngine.Object[] to Texture2D[] ?
I am using this script :
void Start()
{
string dataFileName = "skins";
string tempPath = Path.Combine(Application.persistentDataPath, "AssetData");
tempPath = Path.Combine(tempPath, dataFileName + ".unity3d");
StartCoroutine(LoadObject(tempPath).GetEnumerator());
}
IEnumerable LoadObject(string path)
{
Debug.Log("Loading...");
AssetBundleCreateRequest bundle = AssetBundle.LoadFromFileAsync(path);
yield return bundle;
AssetBundle myLoadedAssetBundle = bundle.assetBundle;
if (myLoadedAssetBundle == null)
{
Debug.Log("Failed to load AssetBundle!");
yield break;
}
AssetBundleRequest request = myLoadedAssetBundle.LoadAllAssetsAsync();
yield return request;
Texture2D[] obj = request.allAssets as Texture2D[];
var path2 = Application.persistentDataPath + "/Item Images/";
if (!Directory.Exists(Path.GetDirectoryName(path2)))
{
Directory.CreateDirectory(Path.GetDirectoryName(path2));
}
foreach (Texture2D s in obj)
{
byte[] itemBGBytes = s.EncodeToPNG();
File.WriteAllBytes(Application.persistentDataPath + "/Item Images/" + s.name + ".png", itemBGBytes);
}
myLoadedAssetBundle.Unload(false);
}
Conversion of Object[] to Texture2D[] is not working. I got this script from the stackoverflow post -> Download AssetBundle in hard disk

If request.allAssets returns object[] which you know are Texture2D , then you can try:
object[] aObj = request.allAssets;
Texture2D[] aT2D = Array.ConvertAll(aObj, x => (Texture2D) x);

Related

JSоn file is not read

I do localization in my game, and I write words in different languages into a JSon file. Everything works in Unity Editor, but on android it throws an exception Cannot find file!
public void LoadLocalizedText(string langName)
{
#if UNITY_ANDROID && !UNITY_EDITOR
string path ="jar:file://" + Application.streamingAssetsPath + "/Languages/" + langName + ".json";
#else
string path = Application.streamingAssetsPath + "/Languages/" + langName + ".json";
#endif
if (File.Exists(path))
{
if (File.Exists(path))
{
string dataAsJson;
#if UNITY_ANDROID && !UNITY_EDITOR
WWW reader = new WWW(path);
UnityWebRequest unityWebRequest = new UnityWebRequest(path);
while (!reader.isDone) { }
dataAsJson = reader.text;
#else
dataAsJson = File.ReadAllText(path);
#endif
LocalizationData loadedData = JsonUtility.FromJson<LocalizationData>(dataAsJson);
localizedText = new Dictionary<string, string>();
for (int i = 0; i < loadedData.items.Length; i++)
{
localizedText.Add(loadedData.items[i].key, loadedData.items[i].value);
}
currentLanguage = langName;
isReady = true;
OnLanguageChanged?.Invoke();
}
else
{
throw new Exception("Cannot find file!");
}
}
You dont need to add "jar:file//" on android for streaming assets path. Also, if you on android, you'll not pass your File.Exists(pass) checks. Here is the working exapmple.

Saving Unity AssetBundle From WebServer to Local Storage using AssetBundle Manager [duplicate]

Right now, it seems UnityWebRequest.GetAssetBundledownload asset to RAM and load. Is there anyway to download to hard disk to load?
This is not really complicated. Handle it like a normal file you would download from the internet but save it with the ".unity3d" extension.
1.Download the AssetBundle as a normal file by making a request with UnityWebRequest.
UnityWebRequest www = UnityWebRequest.Get(url);
yield return www.Send();
2.Retrieve the byte array data with DownloadHandler.data then save it to Application.persistentDataPath/yourfolder/filename.unity3d. Make sure that the extension is ".unity3d".
File.WriteAllBytes(handle.data, data);
That's it.
3.To load the data, use AssetBundle.LoadFromFile or AssetBundle.LoadFromFileAsync:
AssetBundleCreateRequest bundle = AssetBundle.LoadFromFileAsync(path);
If still confused, here is what the thing should look like. You may need to make some modification:
Download and Save:
IEnumerator downloadAsset()
{
string url = "http://url.net/YourAsset.unity3d";
UnityWebRequest www = UnityWebRequest.Get(url);
DownloadHandler handle = www.downloadHandler;
//Send Request and wait
yield return www.Send();
if (www.isError)
{
UnityEngine.Debug.Log("Error while Downloading Data: " + www.error);
}
else
{
UnityEngine.Debug.Log("Success");
//handle.data
//Construct path to save it
string dataFileName = "WaterVehicles";
string tempPath = Path.Combine(Application.persistentDataPath, "AssetData");
tempPath = Path.Combine(tempPath, dataFileName + ".unity3d");
//Save
save(handle.data, tempPath);
}
}
void save(byte[] data, string path)
{
//Create the Directory if it does not exist
if (!Directory.Exists(Path.GetDirectoryName(path)))
{
Directory.CreateDirectory(Path.GetDirectoryName(path));
}
try
{
File.WriteAllBytes(path, data);
Debug.Log("Saved Data to: " + path.Replace("/", "\\"));
}
catch (Exception e)
{
Debug.LogWarning("Failed To Save Data to: " + path.Replace("/", "\\"));
Debug.LogWarning("Error: " + e.Message);
}
}
Load:
IEnumerable LoadObject(string path)
{
AssetBundleCreateRequest bundle = AssetBundle.LoadFromFileAsync(path);
yield return bundle;
AssetBundle myLoadedAssetBundle = bundle.assetBundle;
if (myLoadedAssetBundle == null)
{
Debug.Log("Failed to load AssetBundle!");
yield break;
}
AssetBundleRequest request = myLoadedAssetBundle.LoadAssetAsync<GameObject>("boat");
yield return request;
GameObject obj = request.asset as GameObject;
obj.transform.position = new Vector3(0.08f, -2.345f, 297.54f);
obj.transform.Rotate(350.41f, 400f, 20f);
obj.transform.localScale = new Vector3(1.0518f, 0.998f, 1.1793f);
Instantiate(obj);
myLoadedAssetBundle.Unload(false);
}

Download AssetBundle in hard disk

Right now, it seems UnityWebRequest.GetAssetBundledownload asset to RAM and load. Is there anyway to download to hard disk to load?
This is not really complicated. Handle it like a normal file you would download from the internet but save it with the ".unity3d" extension.
1.Download the AssetBundle as a normal file by making a request with UnityWebRequest.
UnityWebRequest www = UnityWebRequest.Get(url);
yield return www.Send();
2.Retrieve the byte array data with DownloadHandler.data then save it to Application.persistentDataPath/yourfolder/filename.unity3d. Make sure that the extension is ".unity3d".
File.WriteAllBytes(handle.data, data);
That's it.
3.To load the data, use AssetBundle.LoadFromFile or AssetBundle.LoadFromFileAsync:
AssetBundleCreateRequest bundle = AssetBundle.LoadFromFileAsync(path);
If still confused, here is what the thing should look like. You may need to make some modification:
Download and Save:
IEnumerator downloadAsset()
{
string url = "http://url.net/YourAsset.unity3d";
UnityWebRequest www = UnityWebRequest.Get(url);
DownloadHandler handle = www.downloadHandler;
//Send Request and wait
yield return www.Send();
if (www.isError)
{
UnityEngine.Debug.Log("Error while Downloading Data: " + www.error);
}
else
{
UnityEngine.Debug.Log("Success");
//handle.data
//Construct path to save it
string dataFileName = "WaterVehicles";
string tempPath = Path.Combine(Application.persistentDataPath, "AssetData");
tempPath = Path.Combine(tempPath, dataFileName + ".unity3d");
//Save
save(handle.data, tempPath);
}
}
void save(byte[] data, string path)
{
//Create the Directory if it does not exist
if (!Directory.Exists(Path.GetDirectoryName(path)))
{
Directory.CreateDirectory(Path.GetDirectoryName(path));
}
try
{
File.WriteAllBytes(path, data);
Debug.Log("Saved Data to: " + path.Replace("/", "\\"));
}
catch (Exception e)
{
Debug.LogWarning("Failed To Save Data to: " + path.Replace("/", "\\"));
Debug.LogWarning("Error: " + e.Message);
}
}
Load:
IEnumerable LoadObject(string path)
{
AssetBundleCreateRequest bundle = AssetBundle.LoadFromFileAsync(path);
yield return bundle;
AssetBundle myLoadedAssetBundle = bundle.assetBundle;
if (myLoadedAssetBundle == null)
{
Debug.Log("Failed to load AssetBundle!");
yield break;
}
AssetBundleRequest request = myLoadedAssetBundle.LoadAssetAsync<GameObject>("boat");
yield return request;
GameObject obj = request.asset as GameObject;
obj.transform.position = new Vector3(0.08f, -2.345f, 297.54f);
obj.transform.Rotate(350.41f, 400f, 20f);
obj.transform.localScale = new Vector3(1.0518f, 0.998f, 1.1793f);
Instantiate(obj);
myLoadedAssetBundle.Unload(false);
}

Convert from a DataUrl to an Image in C# and write a file with the bytes

Hello I have signature like this:
which is encoded to a DataUrl specifically this string:
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAZAAAADICAYAAADGFbfiAAAYlElEQVR4Xu2dC8w1R1nHQSCIgIKVGLmoiLciFwUs... (long string)"
What i want to do is Convert this DataUrl to an PNG Image, and save the image to the device, this is what i am doing so far:
if (newItem.FieldType == FormFieldType.Signature)
{
if (newItem.ItemValue != null)
{
//string completeImageName = Auth.host + "/" + li[i];
string path;
string filename;
string stringName = newItem.ItemValue;
var base64Data = Regex.Match(stringName, #"data:image/(?<type>.+?),(?<data>.+)").Groups["data"].Value;
var binData = Convert.FromBase64String(base64Data);
path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
filename = Path.Combine(path, base64Data);
if (!File.Exists(filename))
{
using (var stream = new MemoryStream(binData))
{
//Code crashing here--------------------------
File.WriteAllBytes(filename, binData);
}
}
newItem.ItemValue = filename;
}
}
App.Database.SaveReportItem(newItem);
But my code is making my application to crash specifically in this line:
File.WriteAllBytes(filename, binData);
The sample I am using as reference (Link) is using a PictureBox but with Xamarin there is no use of a pictureBox.
Any Ideas?
As #SLaks mentioned I didn't need a MemoryStream, the problem with my code was the path and the filename for further help this is the working code:
if (newItem.FieldType == FormFieldType.Signature)
{
if (newItem.ItemValue != null)
{
//string completeImageName = Auth.host + "/" + li[i];
string path;
string filename;
string stringName = newItem.ItemValue;
var base64Data = Regex.Match(stringName, #"data:image/(?<type>.+?),(?<data>.+)").Groups["data"].Value;
var binData = Convert.FromBase64String(base64Data);
path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
//filename = Path.Combine(path, base64Data.Replace(#"/", string.Empty));
long milliseconds = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
string fileName = "Sn" + milliseconds.ToString() + ".PNG";
filename = Path.Combine(path, fileName);
if (!File.Exists(filename))
{
//using (var stream = new MemoryStream(binData))
//{
File.WriteAllBytes(filename, binData);
//}
}
newItem.ItemValue = filename;
}
}
App.Database.SaveReportItem(newItem);
And the image showed:
I just cleaned Mario's code and fine tuned regex:
public string SaveDataUrlToFile(string dataUrl, string savePath)
{
var matchGroups = Regex.Match(dataUrl, #"^data:((?<type>[\w\/]+))?;base64,(?<data>.+)$").Groups;
var base64Data = matchGroups["data"].Value;
var binData = Convert.FromBase64String(base64Data);
System.IO.File.WriteAllBytes(savePath, binData);
return savePath;
}

Loading an assetbundle from the editor

I've created the ability to download and store an asset bundle to my device. Now I'm trying to load an assetbundle from an already downloaded bundle.
I'm saving the bundle like so:
IEnumerator Start ()
{
WWW urlToLoad = new WWW(url);
yield return urlToLoad;
//read in JSON data
string jsonContents = urlToLoad.text;
var n = JSON.Parse(jsonContents);
jsonURL = n["data"][0];
Debug.Log(jsonURL.ToString());
// split up the json and get last element in teh array
string[] splitJSONURL = jsonURL.Split('/');
string bundle = splitJSONURL[splitJSONURL.Length - 1];
Debug.Log("array: " + bundle.ToString());
//StartCoroutine( DownloadAndCache());
// save bundle to the application folder
string path = Application.persistentDataPath + "/" + bundle;
Debug.Log("Path: " + path);
SaveBytesAsFile(path, urlToLoad.bytes);
savedBundleString = Application.persistentDataPath + "/" + bundle;
}
Next I'm trying to load the bundle like this:
IEnumerator LoadLocalBundle(string filePath)
{
print("Loading from local file..." + filePath);
WWW www = new WWW(filePath);
yield return www;
if(www.error == null)
{
print ("loaded local bundle - instantiating :: " + www.assetBundle.mainAsset.name);
GameObject bundleInstance = (GameObject)Instantiate(www.assetBundle.mainAsset);
assetBundle = www.assetBundle;
}
}
void OnGUI()
{
if (GUI.Button(new Rect(10, 70, 50, 30), "Click"))
{
StartCoroutine( LoadLocalBundle(savedBundleString));
}
}
However, when I run this, nothing loads.
What am I doing wrong?

Categories