I am having a problem with my gallery code, my Android does not recognize the right folder with the .jpg images on the line 20 and 30. It´s a lot different that a PC code cause of the disk details, if someone could help me, i will be a lot gratefull
public class Gallery : MonoBehaviour {
public List<Sprite> gallery = new List<Sprite>();
public Image displayImage;
public Button nextImg;
public Button prevImg;
public int i = 0;
void Start ()
{
// var Images = Directory.GetFiles("C:/Users/Bandeira/Downloads/Menu Start/Assets/Sprite/JPG/","*.jpg");
var Images = Directory.GetFiles("file:///" + "/unitypictures/","*.jpg");
Debug.Log(Images);
StartCoroutine(LoadImages(Images));
}
IEnumerator LoadImages(string[] Images)
{
foreach (var path in Images)
{
Debug.Log(path);
using (var uwr = UnityWebRequestTexture.GetTexture("file:///" + path))
// using (var uwr = UnityWebRequestTexture.GetTexture(path))
{
Debug.Log(path);
yield return uwr.SendWebRequest();
if (uwr.result != UnityWebRequest.Result.Success)
{
Debug.Log(uwr.error);
yield break;
}
var tex = DownloadHandlerTexture.GetContent(uwr);
var sprite = Sprite.Create(tex, new Rect(0f, 0f, tex.width, tex.height), new Vector2(0.5f, 0.5f), 50f, 0, SpriteMeshType.FullRect);
gallery.Add(sprite);
uwr.Dispose();
}
yield return null;
}
}
public void BtnNext (){
if(i + 1 < gallery.Count){
i++;
}
displayImage.sprite = gallery[i];
}
public void BtnPrev () {
if (i - 1 > 0){
i--;
}
displayImage.sprite = gallery[i];
}
}
Dude, I already told you yesterday.
You are using absolute paths, and they cannot work, because for each operating system they are different.
If you connect your Android phone to your computer, or install a file manager, you can see that there should be no folder called "UnityPictures", and even if there is you can't get there easily because I believe they are protected by the device.
The answer is always the same: you can use Persistent data path to save the images and resume them later.
For example you can save them in the Directory (Application.PersistentDataPath + "UnityPictures") and get them back from the same path.
So to be clear: you have to create the folder and insert those images, if you then want to download them.
Alternatively you can also download them from a server. So you could edit them, add more, or remove them without the need for updates, and it would be usable for all devices.
Related
I need some advice on how to use the camera in Xamarin.Forms.
Currently, NuGet Xam.Plugin.Media.
Media. With the following code, when you press a button from the UI, the camera starts up, takes a picture and displays the image on the screen.
private async void OnCameraTapped(object sender, EventArgs e)
{
var photo = await CaptureCamera();
Image.Source = ImageSource.FromStream() =>
{
return new MemoryStream(photo);
});
}
```
```
private async Task<byte[]> CaptureCamera()
{
await Plugin.Media.CrossMedia.Current. Initialize();
Initialize(); if (!Plugin.Media.CrossMedia.Current. IsCameraAvailable ||
!Plugin.Media.CrossMedia.Current. IsTakePhotoSupported)
{
return null;
}
var file = await Plugin.Media.CrossMedia. CrossMedia.
.TakePhotoAsync(
new Plugin.Media.Abstractions. StoreCameraMediaOptions
{
Directory = "Photo",
Name = DateTime.Now.ToString("yyyy_MMdd_HHHmm ") + "Photo.jpg",
});
if (file == null)
return null;
var bytes = new Queue<byte>();
using (var s = file.GetStream())
{
var length = s.Length;
int b;
while ((b = s.ReadByte()) ! = -1)
bytes.Enqueue((byte)b);
}
Dispose();
Dispose(); if (bytes == null) return null;
return bytes.ToArray();
}
However, this method uses Plugin.Media.CrossMedia, which means that the There are some restrictions. I would like to know how to get around those constraints.
Q) I need to press the shutter release and then press "OK" on the activated camera. I want to finish the process by just pressing the shutter release.
Q) The camera I started up defaults to out-camera. I want to take a picture of myself, so I want to start the in-camera as the default.
How can I get around the above two points?
My environment is as follows.
OS Windows 10 Home
IDE Visual Studio 2019 community
Xamarin.Form(.NET Standard 2.1)
Target Android 9.0(API 28)
I'm using this script but I'm not sure how to convert the info array to textures and assign the info images to the textures array.
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Video;
public class StreamVideo : MonoBehaviour
{
public Texture[] frames; // array of textures
public float framesPerSecond = 2.0f; // delay between frames
public RawImage image;
void Start()
{
DirectoryInfo dir = new DirectoryInfo(#"C:\tmp");
string[] extensions = new[] { ".jpg", ".JPG", ".jpeg", ".JPEG", ".png", ".PNG", ".ogg", ".OGG" };
FileInfo[] info = dir.GetFiles().Where(f => extensions.Contains(f.Extension.ToLower())).ToArray();
if (image == null)
{
//Get Raw Image Reference
image = gameObject.GetComponent<RawImage>();
}
}
void Update()
{
int index = (int)(Time.time * framesPerSecond) % frames.Length;
image.texture = frames[index]; //Change The Image
}
}
Then I copied the images from the tmp folder to my project new folder but if I select all the images in the assets I can't drag them to the inspector of the script I can only drag them one by one and it will take time so how can I do it with the script ?
Well you would need to read the according file e.g. using File.ReadAllBytes
Then you could use ImageConversion.LoadImage
I would then do the entire loading process already on app start and later only exchange the texture like e.g.
public class StreamVideo : MonoBehaviour
{
public Texture[] frames; // array of textures
public float framesPerSecond = 2.0f; // delay between frames
public RawImage image;
void Start()
{
DirectoryInfo dir = new DirectoryInfo(#"C:\tmp");
// since you use ToLower() the capitalized version are quite redundant btw ;)
string[] extensions = new[] { ".jpg", ".jpeg", ".png", ".ogg" };
FileInfo[] info = dir.GetFiles().Where(f => extensions.Contains(f.Extension.ToLower())).ToArray();
if (!image)
{
//Get Raw Image Reference
image = gameObject.GetComponent<RawImage>();
}
frames = GetTextures(infos);
}
private Texture[] GetTextures(FileInfo[] fileInfos)
{
var output = new Texture[fileInfos.Length];
for(var i = 0; i < fileInfos.Length; i++)
{
var bytes = File.ReadAllBytes(fileInfos[i].fullName);
output[i] = new Texture2D(1,1);
if(!ImageConversion.LoadImage(output[i], bytes, false))
{
Debug.LogError($"Could not load image from {fileInfos.Length}!", this);
}
}
}
void Update()
{
int index = (int)(Time.time * framesPerSecond) % frames.Length;
image.texture = frames[index]; //Change The Image
}
}
Note: Typed on smartphone but I hope the idea gets clear
You can drag multiple selected images.
First you need to lock your inspector view with a padlock (not possible if you skip that).
Then select all the images, and drop then onto the name_of_the_array (not, into the field). This is just a matter of getting the drag mechanic right, nothing else.
Also, fileinfo reference in your question is a bit confusing, as you are not doing anything with the result anyway.
Have not done that myself yet, but I believe that should work with:
https://docs.unity3d.com/ScriptReference/ImageConversion.LoadImage.html
In the code example there, insteed of "imageAsset.bytes", apply this function to your files (calling FullPath on your FileInfo instances):
https://docs.unity3d.com/ScriptReference/Windows.File.ReadAllBytes.html
I have a Unity game where the player gets one's inventory from the database after starting the game.
I got the pictures of items stored in Firebase Storage, and I can download them.
However, I don't know how to make sprites from the byte[] (fileContents) I get by downloading.
(I'd load these sprites in the player's inventory later)
I got the following C# script:
private void getPlayersInventory()
{
FirebaseDatabase.DefaultInstance.GetReference("users").Child(auth.CurrentUser.UserId)
.Child("inventory").GetValueAsync().ContinueWith(task =>
{
if (task.IsFaulted)
{
print("unable to get snapshot for the inventory");
}
else if (task.IsCompleted)
{
snapshot = task.Result;
if(snapshot.HasChildren)
{
foreach(var current in snapshot.Children)
{
string currentName = current.Value.ToString();
print(currentName.ToLower() + ".png");
const long maxAllowedSize = 10 * 1024 * 1024;
storageReference.Child(currentName.ToLower() + ".png")
.GetBytesAsync(maxAllowedSize)
.ContinueWith((Task<byte[]> task_) =>
{
if (task_.IsFaulted || task_.IsCanceled)
{
Debug.Log(task_.Exception.ToString());
}
else
{
byte[] fileContents = task_.Result;
Debug.Log("Finished downloading!");
}
});
}
}
}
});
}
I believe that you're looking for ImageConversion.LoadImage
Your full code will look something like:
var tex = new Texture(1,1); // note that the size is overridden
tex.LoadImage(task_.Result);
var sprite = Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), new Vector2(tex.width/2, tex.height/2));
You can also pack textures at runtime if that's your eventual goal. Once you get through the tex.LoadImage chunk, you should be able to work out Texture2D.PackTextures.
--Patrick
I still new using UnityWebRequest to download and load asset bundle from server container. The problem is the value for the download progress always 0.
How can I get the value for download progress?
Code Below what I try to download and get the download progress.
//Method to download the assetbundle
IEnumerator DownloadAsset()
{
string url = here the URL for asset bundle;
using (var uwr = new UnityWebRequest(url, UnityWebRequest.kHttpVerbGET))
{
uwr.downloadHandler = new DownloadHandlerAssetBundle(url, 36, 0);
UnityWebRequestAsyncOperation operation = uwr.SendWebRequest();
yield return StartCoroutine(DownloadProgress(operation));
AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(uwr);
{
print("Get asset from bundle...");
}
//Load scene
uwr.Dispose();
print("ready to Load scene from asset...");
StartCoroutine(LoadSceneProgress("Example"));
bundle.Unload(false);
}
}
//Method for download progress
IEnumerator DownloadProgress(UnityWebRequestAsyncOperation operation)
{
while (!operation.isDone)
{
progressBar.color = Color.red;
downloadDataProgress = operation.progress * 100;
progressBar.fillAmount = downloadDataProgress / 100;
print("Download: " + downloadDataProgress);
yield return null;
}
Debug.Log("Done");
}
I expect to display download progress bar or download percentage to show the download progress on screen. but the download progress value always 0.
Instead of
yield return StartCoroutine(DownloadProgress(operation));
the proper way of yielding an IEnumerator is simply
yield return DownloadProgress(operation);
However why not simply do it directly in the same Coroutine?
I would however recommend to rather use UnityWebRequestAssetBundle.GetAssetBundle instead of configurating it from scratch yourself and some other changes:
IEnumerator DownloadAsset()
{
string url = "<here the URL for asset bundle>";
/*
* directly use UnityWebRequestAssetBundle.GetAssetBundle
* instead of "manually" configure and attach the download handler etc
*/
using (var uwr = new UnityWebRequestAssetBundle.GetAssetBundle(url, 36, 0)
{
var operation = uwr.SendWebRequest();
/*
* this should be done only once actually
*/
progressBar.color = Color.red;
while (!operation.isDone)
{
/*
* as BugFinder metnioned in the comments
* what you want to track is uwr.downloadProgress
*/
downloadDataProgress = uwr.downloadProgress * 100;
/*
* use a float division here
* I don't know what type downloadDataProgress is
* but if it is an int than you will always get
* an int division <somethingSmallerThan100>/100 = 0
*/
progressBar.fillAmount = downloadDataProgress / 100.0f;
print("Download: " + downloadDataProgress);
yield return null;
}
AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(uwr);
{
print("Get asset from bundle...");
}
/*
* You do not have to Dispose uwr since the using block does this automatically
*/
//uwr.Dispose();
//Load scene
print("ready to Load scene from asset...");
StartCoroutine(LoadSceneProgress("Example"));
bundle.Unload(false);
}
}
Note from Mayur Asodariya fromt he comments below:
It might happen that your server does not provide the download size and therefore no progress information. In this case you can follow this post to configure your server correctly.
Use following code snippet as a refference:
public IEnumerator ShowDownloadProgress(UnityWebRequest www)
{
while (!www.isDone)
{
LoadingContainer.SetActive(true);
SliderHandle.sprite = Resources.Load<Sprite>("LoadingScreenIcons");
loadingSlider.value = www.downloadProgress*100;
Debug.Log("Download Progress: " +www.downloadProgress);
NewDownloadProgressText.text = (string.Format("{0:0%}", www.downloadProgress));
yield return new WaitForSeconds(.01f);
}
loadingSlider.value = 0;
}
I'm fairly new to C# and Unity so I'm having a little issue here. I'm working on some kind of "photobooth app", which makes the gallery a big part of it. However, I managed to sort out the part of taking screenshots and show them, my problem is that I can't seem to figure out how to delete the pictures from the gallery (I mean, inside the app).
So far, I'm working with this code (just to give it some sense), but this bit erases ALL of the taken pictures, not just the one currently showing.
tring path = Application.persistentDataPath;
DirectoryInfo dir = new DirectoryInfo(path);
FileInfo[] info = dir.GetFiles("*.png");
foreach (FileInfo f in info)
{
File.Delete(f.FullName);
}
I don't know if it'd help, but this is the code I'm using to take and save the screenshots:
yield return new WaitForEndOfFrame();
string timeStamp = System.DateTime.Now.ToString("dd-MM-yyyy-HH-mm-ss");
string fileName = "Screenshot" + timeStamp + ".png";
string pathToSave = fileName;
ScreenCapture.CaptureScreenshot(pathToSave);
yield return new WaitForEndOfFrame();
And, the one I'm using for showing them in the gallery:
public class ScreenShotPreview : MonoBehaviour
{
[SerializeField]
GameObject Panel;
[SerializeField]
string sceneName;
string[] files = null;
int whichScreenShotIsShown = 0;
void Start()
{
files = Directory.GetFiles(Application.persistentDataPath + "/", "*.png");
if (files.Length > 0)
{
GetPictureAndShowIt();
}
}
void GetPictureAndShowIt()
{
string pathToFile = files[whichScreenShotIsShown];
Texture2D texture = GetScreenshotImage(pathToFile);
Sprite sp = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f));
Panel.GetComponent<Image>().sprite = sp;
}
Texture2D GetScreenshotImage(string filePath)
{
Texture2D texture = null;
byte[] fileBytes;
if (File.Exists(filePath))
{
fileBytes = File.ReadAllBytes(filePath);
texture = new Texture2D(2, 2, TextureFormat.RGB24, false);
texture.LoadImage(fileBytes);
}
return texture;
}
public void NextPicture()
{
if (files.Length > 0)
{
whichScreenShotIsShown += 1;
if (whichScreenShotIsShown > files.Length - 1)
whichScreenShotIsShown = 0;
GetPictureAndShowIt();
}
}
public void PreviousPicture()
{
if (files.Length > 0)
{
whichScreenShotIsShown -= 1;
if (whichScreenShotIsShown < 0)
whichScreenShotIsShown = files.Length - 1;
GetPictureAndShowIt();
}
}
I hope it makes sense? Thank you in advance!
TLDR; Can't figure out how to delete current picture showing in the gallery.
Your file paths are stored in the string[] files variable. The whichScreenShotIsShown variable is the current index that determines which path is currently being displayed. These two variables are declared inside the ScreenShotPreview script.
Therefore to delete the current file, you would do something like this:
string currentFile = files[whichScreenShotIsShown];
File.Delete(currentFile );