unity how to load image from streamingassets on ios - c#

I put some png files into /Assets/StreamingAssets, what i want to do is load a image's texture from that floder.
here is my c# code below:
string path = "file://" + Application.streamingAssetsPath + "/sunny.png";
private IEnumerator GetMatByWWW(string url)
{
WWW www = new WWW(url);
yield return www;
RawImage rawImage = gameObject.GetComponent<RawImage>();
rawImage.texture = www.texture;
}
On OSX, the code working perfect. But i need to make it working on IOS. So i remove the prefix of "file://" and the path is :
string path = Application.streamingAssetsPath + "/sunny.png";
It just showed a red question-mark after build and run at my iPhone. And i also tried
string path = "file:/" + Application.streamingAssetsPath + "/sunny.png";
Who can tell me how to do it correctly?

string ab_path = Application.streamingAssetsPath + "/" + "bundlename";
AssetBundle ab = AssetBundle.LoadFromFile(ab_path);
if(ab == null)
{
Debug.Log("ab is null");
}
Gameobject prefab = ab.LoadAsset<GameObject>("prefab_name");
Gameobject go = GameObject.Instantiate(prefab);
please check this link.
https://docs.unity3d.com/ScriptReference/AssetBundle.LoadFromFile.html

Related

Access Images and videos from android internal Storage using Unity C#

i am trying to access the Whatsapp folder from android internal storage but for some reason this code is not working the file path is correct but this if statement never gets true
here is the code for checking if file exixts
public static Texture2D LoadPNG()
{
Texture2D tex = null;
byte[] fileData;
if (File.Exists(filePath))
{
Debug.Log("file exists");
fileData = File.ReadAllBytes(filePath);
tex = new Texture2D(2, 2);
tex.LoadImage(fileData); //..this will auto-resize the texture dimensions.
}
return tex;
}
now filepath = "/storage/emulated/0/Whatsapp/Media/.statuses
code which makes this path
public static string GetDownloadFolder()
{
string[] temp = (Application.persistentDataPath.Replace("Android", "")).Split(new string[] { "//" }, System.StringSplitOptions.None);
filePath = temp[0]+"/WhatsApp/Media/.Statuses";
return (temp[0] + "/WhatsApp/Media/.Statuses");
}
now problem is that in android device this .statuses folder have images and video files but this if statement never gets called why i dont understand even path is correct
if (File.Exists(filePath))
{
Debug.Log("file exists");
fileData = File.ReadAllBytes(filePath);
tex = new Texture2D(2, 2);
tex.LoadImage(fileData); //..this will auto-resize the texture dimensions.
}
Your problem is that you check if file exists at folder path.
The solution is check if path is directory and get all files from it:
if (Directory.Exists(path))
{
string filenames[] = Directory.GetFiles(path);
foreach (var filename in filenames)
{
LoadPNG(filename);
}
}

Simple Image Upload from Unity to Firebase not working

I am working on an IOS App which I create with Unity in C# (Unity 2018.2.5f1). Now I'm trying to upload an image to Firebase Storage to get familiar with it. Unfortunately this doesn't work.
I assume there is a problem with the path to the local file. I get the following error in XCode when running the app.
Firebase.Storage.Storage.StorageException: There is no object at the desired reference.
The file swift.jpg definitively exists on the iPhone.
Your help is very welcome.
using UnityEngine;
using Firebase.Storage;
using System.Threading.Tasks;
public class Upload : MonoBehaviour {
FirebaseStorage storage;
StorageReference storage_ref;
// Use this for initialization
void Start () {
storage = FirebaseStorage.DefaultInstance;
storage_ref = storage.GetReferenceFromUrl("gs://[My Storage URL]");
// File located on disk
string local_file = Application.persistentDataPath + "/" + "swift.jpg";
// Create a reference to the file you want to upload
StorageReference image_ref = storage_ref.Child("images/swift.jpeg");
// Upload the file to the path
image_ref.PutFileAsync(local_file)
.ContinueWith((Task<StorageMetadata> task) => {
if (task.IsFaulted || task.IsCanceled) {
Debug.Log(task.Exception.ToString());
// Uh-oh, an error occurred!
}
else {
// Metadata contains file metadata such as size, content-type, and download URL.
// StorageMetadata metadata = task.Result;
// string download_url = metadata.DownloadUrl.ToString();
// Debug.Log("Finished uploading...");
// Debug.Log("download url = " + download_url);
}
});
}
}
Try
string local_file = "file:///" + Application.persistentDataPath + "/" + "swift.jpg";
Or
string local_file = "file://" + Application.persistentDataPath + "/" + "swift.jpg";
Or
string local_file = "file:\\" + Application.persistentDataPath + "/" + "swift.jpg";
Hope one of these will work.

Unity Streaming Assets iOS not working

I've made an app in Unity which has been on the Google Play Store for over a year. Today I wanted to deployt it on Apple App Market but the translations don't work there.
I use the following code to load my app translations
public bool LoadLocalizedText(SystemLanguage language)
{
localizedText = new Dictionary<string, string>();
string filePath = Path.Combine(Application.streamingAssetsPath, "localizedText_" + language + ".json");
WWW reader = new WWW(filePath);
if (reader.text == null || reader.text == "") return false;
while (!reader.isDone) { }
string dataAsJson;
dataAsJson = reader.text;
LocalizationData loadedData = JsonUtility.FromJson<LocalizationData>(dataAsJson);
for (int i = 0; i < loadedData.items.Length; i++)
{
localizedText.Add(loadedData.items[i].key, loadedData.items[i].value);
}
Debug.Log("Data loaded, dictionary contains: " + localizedText.Count + " entries");
if (localizedText.Count == 0) return false;
else
{
isReady = true;
return true;
}
}
Yet somehow, all text fields display "Localized Text Not Found" because it cannot find my Assets... what could this be?
Is this because the StreamingAssets folder isn't copied to xCode?
Is it because the location is different on iOS?
Something else?
This is my folder structure
The WWW or UnityWebRequest API is used to read files on the StreamingAssets on Android. For iOS, The any API from the System.IO namespace such as System.IO.File.ReadAllText should be used.
Something like this:
IEnumerator ReadFromStreamingAssets()
{
string filePath = System.IO.Path.Combine(Application.streamingAssetsPath, "MyFile");
string result = "";
if (filePath.Contains("://"))
{
UnityEngine.Networking.UnityWebRequest www = UnityEngine.Networking.UnityWebRequest.Get(filePath);
yield return www.SendWebRequest();
result = www.downloadHandler.text;
}
else
result = System.IO.File.ReadAllText(filePath);
}
Also, the WWW API is made to be used in a coroutine function so that you can wait or yield it until the download is complete. Your while (!reader.isDone) { } can freeze Unity. That should be while (!reader.isDone) yield return null; which waits every frame until download is finished. The LoadLocalizedText function must also be a coroutine function so the return type should be IEnumerator instead of bool. To make it return bool too, use Action<bool> as parameter.
After fixing both issues, below is what the new code should look like:
public IEnumerator LoadLocalizedText(SystemLanguage language, Action<bool> success)
{
localizedText = new Dictionary<string, string>();
string filePath = Path.Combine(Application.streamingAssetsPath, "localizedText_" + language + ".json");
string dataAsJson;
//Android
if (filePath.Contains("://"))
{
WWW reader = new WWW(filePath);
//Wait(Non blocking until download is done)
while (!reader.isDone)
{
yield return null;
}
if (reader.text == null || reader.text == "")
{
success(false);
//Just like return false
yield break;
}
dataAsJson = reader.text;
}
//iOS
else
{
dataAsJson = System.IO.File.ReadAllText(filePath);
}
LocalizationData loadedData = JsonUtility.FromJson<LocalizationData>(dataAsJson);
for (int i = 0; i < loadedData.items.Length; i++)
{
localizedText.Add(loadedData.items[i].key, loadedData.items[i].value);
}
Debug.Log("Data loaded, dictionary contains: " + localizedText.Count + " entries");
if (localizedText.Count == 0)
success(false);
else
{
isReady = true;
success(true);
}
}
And used like this:
StartCoroutine(LoadLocalizedText(languageInstance, (status) =>
{
if (status)
{
//Success
}
}));
JsonUtility has a problem with iOS so it doesn't work
and if you test in local use File.OpenRead(path) works in iOS
filePath = Application.streamingAssetsPath
StreamReader streamReader = new StreamReader(File.OpenRead(string.Format("{0}/{1}.txt", filePath, fileName)));
and streamingAssets read only if you want to write the file in iOS use this path -> Application.persistentDataPath
Actually the problem is that Application.streamingAssetsPath is not fully correct for iOS device. You need to add "file://" manually to the path as well. Please note that it should be done outside of Path.Combine() method because for some reason, Combine() method strips it =) I wasted couple of hours trying to understand what is going wrong and I hope my post will save someone's time. Proper way to do is: filePath = "file://" System.IO.Path.Combine(Application.streamingAssetsPath, "MyFile"); The rest of the code is the same (this is true for AssetBundles as well)

Receive image from web server C# Unity

I have had web server that stores the images. In Unity, I can receive one and create gameobject to change it's material. However, I want to receive max no. four images. After 1 mins, I want to receive max no. four images again. Besides, if there is two images in server, I just want to create two new gameobject and change them material. If there is three, just create three. How can I do that, Any one can help me? Here is my code in Unity:
void Start () {
StartCoroutine (LoadImage ());
}
IEnumerator LoadImage(){
filename = "image" + k.ToString () + ".png";
url = "https://wwwfoodparadisehk.000webhostapp.com/" + filename;
WWW www = new WWW (url);
yield return www;
if (www.error != null) {
Debug.Log (www.error);
} else {
Debug.Log (k);
path = "Assets/MyMaterial" + k.ToString () + ".mat";
k = k + 1;
material = new Material (Shader.Find ("Sprites/Default"));
AssetDatabase.CreateAsset (material, path);
Debug.Log (AssetDatabase.GetAssetPath (material));
material.mainTexture = www.texture;
GameObject newPaperInstance = Instantiate (newpaper) as GameObject;
newPaperInstance.transform.Find ("Plane001").gameObject.GetComponent<Renderer> ().material = material;
}
}
I'd first ask my server for a list of the items I can get. For this, you can simply make a text file or make your own PHP file to create a list that you separate by a character like the pipe (|):
MyMaterial1|MyMaterial2|MyMaterial3
Then you can ask the file from your server the same way you'd get the images and create a string[] array object from the result. You can use Split('|') in order to create this array from your result string.
When you're done, you can foreach over the items within the array.
IEnumerator LoadImages()
{
string filename = "imagelist.txt";
string url = "https://wwwfoodparadisehk.000webhostapp.com/" + filename;
WWW www = new WWW (url);
yield return www;
if (www.error != null)
{
Debug.Log (www.error);
}
else
{
string[] images = www.text.Split ('|');
foreach (var image in images)
{
LoadImage (image);
}
}
}
Last but not least, you'll have to create a second function that loads the texture from the string you supply:
IEnumerator LoadImage(string image)
{
string url = "https://wwwfoodparadisehk.000webhostapp.com/" + image;
WWW www = new WWW (url);
yield return www;
if (www.error != null)
{
Debug.Log (www.error);
}
else
{
// turn your image into a texture with www.texture and apply it to your objects.
}

Loading an image as Texture2D

In my program, I want to save some screenshots and load them later on to compute somethings. I created a methode to compute the image names:
static public string generatePhotoName (string cameraName, float time)
{
return "G:/Data/unity/cameraDemo/" +
DataController.measurmentPath +
"/photos" + "/" +
cameraName + "/" +
time.ToString () + "_" + cameraName + ".png";
}
This worked fine for saving, but when I try to load an image, File.Exists (filePath)returns false.
But when I hardcoded the filepath, loading works fine too:
static public string generatePhotoName (string cameraName, float time)
{
return "G:/Data/unity/cameraDemo/demo/photos/Camera/test.png";
}
It even works with "real" image names(i.e. 3.827817_Camera.png).
Using Path.Combine(...) and changing "/" to "\" did not change anything...
// edit: this is my load methode
static public Texture2D loadPhotoToTexture (string filePath)
{
Texture2D tex = null;
byte[] fileData;
if (File.Exists (filePath)) {
fileData = File.ReadAllBytes (filePath);
tex = new Texture2D (2, 2);
tex.LoadImage (fileData); //..this will auto-resize the texture dimensions.
} else {
Debug.Log (filePath + " does not exist");
}
return tex;
}`
// edit2: some more code
This is how I call the methode
Texture2D photo = DataController.loadPhotoToTexture(photoData.getFileName ());
And this is my class PhotoData
public class PhotoData : BaseData
{
private string _cameraName;
public string cameraName {
get { return _cameraName; }
set { _cameraName = value; }
}
private float _time;
public float time {
get { return _time; }
set { _time = value; }
}
public PhotoData ()
{
}
public PhotoData (string cameraName, float time)
{
_cameraName = cameraName;
_time = time;
}
public string getFileName ()
{
return PlayerController.generatePhotoName (_cameraName, _time);
}
}
The problem was, that I tried to save and load the screenshots in one Update()-call.
I fixed it by changing it to right-click to take and save a screenshot and left-click to load the screenshot.
If you want to store images to a certain file on disk, not inside your game folder structure, do this: create a folder, and store its location (filepath). For example:
string screenshotFileName = time.ToString () + "_" + cameraName + ".png"
string screenshotDirectory;
screenshotDirectory = #"C:\someFolder\anotherFolder\";
try { Directory.CreateDirectory(directory); }
catch (Exception e)
{ //you should catch each exception separately
if (e is DirectoryNotFoundException || e is UnauthorizedAccessException)
Debug.LogError("OMG PANIC");
}
FileInfo filepath = new FileInfo(screenshotDirectory+screenshotFileName);
if(filepath.Exists)
{
//load the file
}
You could also simply create a folder, with a relative path, which will be in the same folder as your executable, by changing the screenshotDirectory to
screenshotDirectory = #"screenshots\"+cameraName+#"\";
Edit:
You seem to load the texture correctly. Are you assigning it to the material's main texture? Where is your code encountering the problem? For example if you're running this script on the same object that you want the texture to be applied:
this.GetComponent<Renderer>().material.mainTexture = loadedTexture;
Also, when you want to load images, it's best that you use the Resources folder, which uses forwards slashes, not . Store everything that you might want to load on runtime there, and use Resources.Load().

Categories

Resources