Saving an Image to Photos Folder In hololens App - c#

I'm attempting to capture a photo inside my hololens app. It seems to be working but saving the image to an obscure place that I cant access or view. I want to save it to my pictures library Described here I think. Or where should i save the image so I can see it in my photos on the hololens.
filePath = C:/Data/Users/JanikJoe/AppData/Local/Packages/HoloToolkit-Unity_pzq3xp76mxafg/LocalState\CapturedImage10.02831_n.jpg
filePath2 = C:/Data/Users/DefaultAccount/AppData/Local/DevelopmentFiles/HoloToolkit-UnityVS.Debug_x86.janik/Data\CapturedImage10.02831_n.jpg
using UnityEngine;
using UnityEngine.VR.WSA.WebCam;
using System.Linq;
public class PhotoCaptureFVTC : MonoBehaviour {
UnityEngine.VR.WSA.WebCam.PhotoCapture photoCaptureObject = null;
// Use this for initialization
void Start()
{
Debug.Log("snap pic taken");
PhotoCapture.CreateAsync(false, OnPhotoCaptureCreated);
}
public void OnPhotoCaptureCreated(PhotoCapture captureObject)
{
photoCaptureObject = captureObject;
//Resolution cameraResolution = PhotoCapture.SupportedResolutions.OrderByDescending((res) => res.width * res.height).First();
Resolution cameraResolution = PhotoCapture.SupportedResolutions.OrderByDescending((res) => res.width * res.height).First();
CameraParameters c = new CameraParameters();
c.hologramOpacity = 0.0f;
c.cameraResolutionWidth = cameraResolution.width;
c.cameraResolutionHeight = cameraResolution.height;
c.pixelFormat = CapturePixelFormat.BGRA32;
captureObject.StartPhotoModeAsync(c, false, OnPhotoModeStarted);
}
void OnStoppedPhotoMode(PhotoCapture.PhotoCaptureResult result)
{
photoCaptureObject.Dispose();
photoCaptureObject = null;
}
private void OnPhotoModeStarted(PhotoCapture.PhotoCaptureResult result)
{
if (result.success)
{
string filename = string.Format(#"CapturedImage{0}_n.jpg", Time.time);
string filePath = System.IO.Path.Combine(Application.persistentDataPath, filename);
string filePath2 = System.IO.Path.Combine(Application.dataPath, filename);
photoCaptureObject.TakePhotoAsync(filePath, PhotoCaptureFileOutputFormat.JPG, OnCapturedPhotoToDisk);
Debug.LogError("Saved That Image Somewhere" +"FileName: ="+ filename + " FilePath: = " + filePath + " FilePath2: = " + filePath2);
}
else
{
Debug.LogError("Unable to start photo mode!");
}
}
void OnCapturedPhotoToDisk(PhotoCapture.PhotoCaptureResult result)
{
if (result.success)
{
Debug.Log("Saved Photo to disk!");
photoCaptureObject.StopPhotoModeAsync(OnStoppedPhotoMode);
}
else
{
Debug.Log("Failed to save Photo to disk");
}
}
}

It seems to be that it is not possible to save directly in the camera roll folder and there is no picture library on the HoloLens.
There is the same question here: https://forums.hololens.com/discussion/1458/capturing-photo-in-unity-and-saving-to-disk
I tried the workaround and it works fine. Just move the saved image to the camera roll folder.
#if !UNITY_EDITOR && UNITY_WINRT_10_0
var cameraRollFolder = Windows.Storage.KnownFolders.CameraRoll.Path;
File.Move(_filePath, Path.Combine(cameraRollFolder, _filename));
#endif

Related

The IEnumerator with voice command function

I have a project where I use only voice command to perform some different function and one of them is to take a photo using Hololens. So I use the StartCoroutine(photoshoot()); function to call the IEnumerator photoshoot(). The IEnumerator photoshoot() call the TakePhotosnap();.
It takes the photo perfectly but I have issue after taking the photo it doesn't go back to IEnumerator.
It stops the code and can't perform any other function.
As you can see in my code ( I put some numbers to help me explain the function )
I call StartCoroutine(photoshoot()); line 11 and in IEnumerator photoshoot() called the TakePhotosnap(); line 12 and it performs taking photo till line 13 Debug.Log("we finish taking photo successfully "); and then stop. It should go to line 14 in IEnumerator photoshoot().
Here is some of my code
private void Takephoto()
{
// this function is to call to take a photo and save it in a special folder
Debug.Log("Take Photo function call is started");
11 StartCoroutine(photoshoot());
Debug.Log("Take Photo for Hololens");
}
IEnumerator photoshoot()
{
Debug.Log(" The taking photo coroutine is started ");
yield return new WaitForEndOfFrame();
Debug.Log("Take Photo");
12 TakePhotosnap();
14 Debug.Log("Finish taking Hi again ");
yield return new WaitForEndOfFrame();
GameObject.Find("Cube").transform.localPosition = new Vector3(Random.Range(-1, 1), 0, Random.Range(1, 3));
GameObject.Find("Cube").SetActive(true);
}
--------------------------------------------
private void TakePhotosnap()
{
Debug.Log("TakePhoto Call StartPhotoModeAsync () method to start the photo mode");
Debug.Log("snap pic taken");
PhotoCapture.CreateAsync(false, OnPhotoCaptureCreated);
}
void OnPhotoCaptureCreated(PhotoCapture captureObject)
{
//Store objects, configure shooting parameters and start shooting mode.
Debug.Log("Start taking photo calling function");
photoCaptureObject = captureObject;
Debug.Log("set camera parameters");
Resolution cameraResolution = PhotoCapture.SupportedResolutions.OrderByDescending((res) => res.width * res.height).First();
CameraParameters c = new CameraParameters();
/// c= CameraParameters
c.hologramOpacity = 1.0f;
c.cameraResolutionWidth = cameraResolution.width;
c.cameraResolutionHeight = cameraResolution.height;
c.pixelFormat = CapturePixelFormat.BGRA32;
Debug.Log("camera parameters finish");
captureObject.StartPhotoModeAsync(c, OnPhotoModeStarted);
}
private void OnPhotoModeStarted(PhotoCapture.PhotoCaptureResult result)
{
if (result.success)
{
//string filename = string.Format(#"CapturedImage{0}_n.jpg", Time.time);
string filename = string.Format(#"alc.jpg", Time.time);
Debug.Log("FileName: =" + filename);
string filePath = System.IO.Path.Combine(Application.persistentDataPath, filename);
Debug.Log("filePath: =" + filePath);
/////
string targetPath = #"C: \Users\ABC\Pictures\Camera Roll";
string destFile = System.IO.Path.Combine(targetPath, filename);
Debug.Log("destFile: =" + destFile);
if (!System.IO.File.Exists(filePath))
{
//System.IO.File.Create(filePath);
System.IO.File.Create(filePath).Dispose();
}
// https://blog.csdn.net/Lee_gc/java/article/details/79919042
Debug.Log("filePath filePath: =" + filePath);
string filePath2 = System.IO.Path.Combine(Application.dataPath, filename);
Debug.Log("filePath2: =" + filePath2);
Debug.Log("finish to set photo file path and name");
//photoCaptureObject.TakePhotoAsync(filePath, PhotoCaptureFileOutputFormat.JPG, OnCapturedPhotoToDisk);
Debug.LogError("Saved That Image Somewhere" + "FileName: =" + filename + " FilePath: = " + filePath + " FilePath2: = " + filePath2);
Debug.Log("finish to copy photo to new directory");
Debug.Log("finish photo");
photoCaptureObject.TakePhotoAsync(filePath, PhotoCaptureFileOutputFormat.JPG, OnCapturedPhotoToDisk);
13 Debug.Log("we finish taking photo successfuly ");
}
else
{
Debug.LogError("Unable to start photo mode!");
}
}
// clean up
void OnStoppedPhotoMode(PhotoCapture.PhotoCaptureResult result)
{
Debug.Log("result=" + result);
photoCaptureObject.Dispose();
photoCaptureObject = null;
}
void OnCapturedPhotoToDisk(PhotoCapture.PhotoCaptureResult result)
{
if (result.success)
{
Debug.Log("Saved Photo to disk!");
photoCaptureObject.StopPhotoModeAsync(OnStoppedPhotoMode);
}
else
{
Debug.Log("Failed to save Photo to disk");
}
}
}
What is wrong with my code? Is there any other way to solve it?
In fact, code 14 runs earlier than you think. In TakePhotosnap function, when the asynchronous method PhotoCapture.CreateAsync() is run to, this method will return control to the calling method, and then "Finish taking Hi again" will be output Immediately.
In addition, also because of the asynchronous, code 13 will be output before any result returned from TakePhotoAsync method, so it does not mark the photo was taken successfully.
Therefore, we recommend that you add breakpoints to your code to determine whether code 14 is executed, and try to move the log statement to callback. For example:
photoCaptureObject.TakePhotoAsync(filePath, PhotoCaptureFileOutputFormat.JPG, OnCapturedPhotoToDisk);
Debug.Log("we finish taking photo successfuly ");
=>
photoCaptureObject.TakePhotoAsync(filePath, PhotoCaptureFileOutputFormat.JPG, OnCapturedPhotoToDisk);
void OnCapturedPhotoToDisk(PhotoCapture.PhotoCaptureResult result)
{
if (result.success)
{
Debug.Log("we finish taking photo successfuly ");
}
}
Besides, this doc is worth reading through for you: Asynchronous programming with async and await

Driver is null when taking a screenshot

In my spec-flow project, I have created static Screenshot class. I have also created static methods to take screen shots. But at run time, my driver is consistently null. How can I solve this problem.
Below is the code snippet:
public static class Screenshot
{
public static void TakeScreenshots(this IWebDriver driver, string path = #"result")
{
var takescreenshot = (driver as ITakesScreenshot) != null;
if (!takescreenshot)
return;
var filename = string.Empty + DateTime.Now.Hour + DateTime.Now.Minute + DateTime.Now.Second + DateTime.Now.Millisecond;
filename = path + #"\" + filename + ".png";
var ss = ((ITakesScreenshot)driver).GetScreenshot();
var screenshot = ss.AsBase64EncodedString;
byte[] screenshotAsByteArray = ss.AsByteArray;
ss.SaveAsFile(filename, ScreenshotImageFormat.Png);
}
}
I call in my afterstep hook like so:
[AfterStep()]
public static void AfterStep()
{
if (ScenarioContext.Current.TestError == null)
{
stepStatus = Status.Pass;
}
else
{
ScreenShot.TakeScreenshots(driver);
}
test.Log(stepStatus, stepLogText);
}

Asp.Net Mvc Delete file issue

I have an issue with Files.
I am doing an image importer so clients put their files on an FTP server and then they can import it in the application.
During the import process I copy the file in the FTP Folder to another folder with File.copy
public List<Visuel> ImportVisuel(int galerieId, string[] images)
{
Galerie targetGalerie = MemoryCache.GetGaleriById(galerieId);
List<FormatImage> listeFormats = MemoryCache.FormatImageToList();
int i = 0;
List<Visuel> visuelAddList = new List<Visuel>();
List<Visuel> visuelUpdateList = new List<Visuel>();
List<Visuel> returnList = new List<Visuel>();
foreach (string item in images)
{
i++;
Progress.ImportProgress[Progress.Guid] = "Image " + i + " sur " + images.Count() + " importées";
string extension = Path.GetExtension(item);
string fileName = Path.GetFileName(item);
string originalPath = HttpContext.Current.Request.PhysicalApplicationPath + "Uploads\\";
string destinationPath = HttpContext.Current.Server.MapPath("~/Images/Catalogue") + "\\";
Visuel importImage = MemoryCache.GetVisuelByFilName(fileName);
bool update = true;
if (importImage == null) { importImage = new Visuel(); update = false; }
Size imageSize = importImage.GetJpegImageSize(originalPath + fileName);
FormatImage format = listeFormats.Where(f => f.width == imageSize.Width && f.height == imageSize.Height).FirstOrDefault();
string saveFileName = Guid.NewGuid() + extension;
File.Copy(originalPath + fileName, destinationPath + saveFileName);
if (format != null)
{
importImage.format = format;
switch (format.key)
{
case "Catalogue":
importImage.fileName = saveFileName;
importImage.originalFileName = fileName;
importImage.dossier = targetGalerie;
importImage.dossier_id = targetGalerie.id;
importImage.filePath = "Images/Catalogue/";
importImage.largeur = imageSize.Width;
importImage.hauteur = imageSize.Height;
importImage.isRoot = true;
if (update == false) { MemoryCache.Add(ref importImage); returnList.Add(importImage); }
if (update == true) visuelUpdateList.Add(importImage);
foreach (FormatImage f in listeFormats)
{
if (f.key.StartsWith("Catalogue_"))
{
string[] keys = f.key.Split('_');
string destinationFileName = saveFileName.Insert(saveFileName.IndexOf('.'), "-" + keys[1].ToString());
string destinationFileNameDeclinaison = destinationPath + destinationFileName;
VisuelResizer declinaison = new VisuelResizer();
declinaison.Save(originalPath + fileName, f.width, f.height, 1000, destinationFileNameDeclinaison);
Visuel visuel = MemoryCache.GetVisuelByFilName(fileName.Insert(fileName.IndexOf('.'), "-" + keys[1].ToString()));
update = true;
if (visuel == null) { visuel = new Visuel(); update = false; }
visuel.parent = importImage;
visuel.filePath = "Images/Catalogue/";
visuel.fileName = destinationFileName;
visuel.originalFileName = string.Empty;
visuel.format = f;
//visuel.dossier = targetGalerie; On s'en fout pour les déclinaisons
visuel.largeur = f.width;
visuel.hauteur = f.height;
if (update == false)
{
visuelAddList.Add(visuel);
}
else
{
visuelUpdateList.Add(visuel);
}
//importImage.declinaisons.Add(visuel);
}
}
break;
}
}
}
MemoryCache.Add(ref visuelAddList);
// FONCTION à implémenter
MemoryCache.Update(ref visuelUpdateList);
return returnList;
}
After some processes on the copy (the original file is no more used)
the client have a pop-up asking him if he wants to delete the original files in the ftp folder.
If he clicks on Ok another method is called on the same controller
and this method use
public void DeleteImageFile(string[] files)
{
for (int i = 0; i < files.Length; i++)
{
File.Delete(HttpContext.Current.Request.PhysicalApplicationPath + files[i].Replace(#"/", #"\"));
}
}
This method works fine and really delete the good files when I use it in other context.
But here I have an error message:
Process can't acces to file ... because it's used by another process.
Someone have an idea?
Thank you.
Here's the screenshot of Process Explorer
There are couple of thing you can do here.
1) If you can repro it, you can use Process Explorer at that moment and see which process is locking the file and if the process is ur process then making sure that you close the file handle after your work is done.
2) Use try/catch around the delete statement and retry after few seconds to see if the file handle was released.
3) If you can do it offline you can put in some queue and do the deletion on it later on.
You solve this by using c# locks. Just embed your code inside a lock statement and your threads will be safe and wait each other to complete processing.
I found the solution:
in my import method, there a call to that method
public void Save(string originalFile, int maxWidth, int maxHeight, int quality, string filePath)
{
Bitmap image = new Bitmap(originalFile);
Save(ref image, maxWidth, maxHeight, quality, filePath);
}
The bitmap maintains the file opened blocking delete.
just added
image.Dispose();
in the methos and it work fine.
Thank you for your help, and thank you for process explorer. Very useful tool

Web service not working in web player build Unity5

I am trying to get product description from server using web service. This is working fine in unity editor but when i created web player build it's not working.
what should be the problem ? Why it is not working in web player build ?
this is the sample code i am trying :
public void product_detail()
{
string url = "http://*****/api.php?method=get_product_detail&product_id=" + name + "";
Debug.Log(url);
WWW www = new WWW(url);
StartCoroutine(WaitForRequest1(www));
}
IEnumerator WaitForRequest1(WWW www)
{
yield return www;
// check for errors.
if (www.error == null)
{
Debug.Log("WWW data: " + www.data);
Processjson(www.data);
}
else
{
Debug.Log("WWW Error: " + www.error);
}
}
private void Processjson(string jsonString)
{
JsonData jsonvale = JsonMapper.ToObject(jsonString);
var vc = JsonConvert.DeserializeObject(jsonString,typeof(Rootobject)) as Rootobject;
//string status = jsonString;
p_deail = jsonvale["detail"].ToString();
p_price = jsonvale["price"].ToString();
PlayerPrefs.SetString ("P_detail",p_deail);
PlayerPrefs.SetString ("P1_price",p_price);
Component com = GameObject.Find("FPSController").GetComponent("FirstPersonController") as MonoBehaviour;
(com as MonoBehaviour).enabled = false;
PlayerPrefs.SetString("Product",prefab.name.ToString());
GUIWindow.SetActive(true);
GameObject clone = Instantiate (prefab, Vector3.zero, Quaternion.identity) as GameObject;
clone.AddComponent<zoomC>();
clone.AddComponent<rotatC>();
clone.transform.position = Camera.main.transform.position + Camera.main.transform.forward*1.0f + Camera.main.transform.right*-0.5f + Camera.main.transform.up*-0.2f;
clone.transform.rotation = new Quaternion( Camera.main.transform.rotation.x, Camera.main.transform.rotation.y, Camera.main.transform.rotation.z, Camera.main.transform.rotation.w );
clone.transform.localScale = new Vector3(0.5f,0.5f,0.5f);
}

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