how to save image on android in unity - c#

I'm new in Unity and I'm trying to save an image for get it after. I try Application.CaptureScreenshot and the method with Texture2D.ReadPixel, i try to save in persistentDataPath (/data/user/0/my.package.name/files/), in /sdcard/Download/ and in /storage/emulated/0/Download. No method worked. In every manifest of my project I have WRITE_EXTERNAL_STORAGE permission. If I save to persistent data, I don't found it I found only cache of UnityAds, and if I save to Download folder I get access denied.
Anyone can help me?
Here's my code :
IEnumerator ScreenShot(){
yield return new WaitForEndOfFrame ();
Application.CaptureScreenshot ("ball.png");
Application.CaptureScreenshot ("/sdcard/Download/ball.png");
int width = Screen.width;
int height = Screen.height;
Texture2D tex = new Texture2D (width, height, TextureFormat.RGB24, false);
tex.ReadPixels (new Rect (0, 0, width, height), 0, 0);
tex.Apply ();
byte[] bytes = tex.EncodeToJPG ();
File.WriteAllBytes ("sdcard/Download/ball.png", bytes);
File.WriteAllBytes (Application.persistentDataPath + "/ball.png", bytes);
}
Before i check if folders exist :
if(!System.IO.Directory.Exists("/sdcard/Download/"))
{
System.IO.Directory.CreateDirectory ("/sdcard/Download/");
}
if(!System.IO.Directory.Exists(Application.persistentDataPath))
{
System.IO.Directory.CreateDirectory (Application.persistentDataPath);
}
And I start IEnumerator with:
StartCoroutine(ScreenShot());
What I'm doing wrong?

Here is what works for me:
string destination = DateTime.Now.ToString ("yyyy-MM-dd-HHmmss") + ".png";
string fullDestination = Path.Combine (Application.persistentDataPath, destination);
Application.CaptureScreenshot (destination);
SharingWriter.WriteTextInstant ("Preparing...");
FileInfo fileInfo = new FileInfo(fullDestination);
while(fileInfo == null || fileInfo.Exists == false)
{
yield return null;
fileInfo = new FileInfo(fullDestination);
}
Application.CaptureScreenshot handles everything, no need to worry about reading pixels and writing to files that's redundant. Just have a while loop afterwards in the Coroutine to wait for the magic to happen! I used this to create screenshot sharing functionality for mobile.

Related

Unity Upload Image To Server With Codeigniter Not Working

I want to upload an image jpg to my server. I have try but it didn't work.
I don't what cause the upload failed.
Below the detail code.
Unity C#
public void TakePicture(int maxSize)
{
if (NativeCamera.IsCameraBusy())
{
Debug.Log("Camera Busy");
return;
}
else
{
NativeCamera.Permission permission = NativeCamera.TakePicture((path) =>
{
Debug.Log("Image path: " + path);
if (path != null)
{
// Create a Texture2D from the captured image
Texture2D texture = NativeCamera.LoadImageAtPath(path, maxSize);
//snap.SetPixels(tex.GetPixels());
byte[] bytes = File.ReadAllBytes(path);
Debug.Log("Bytes:" + bytes);
Destroy(texture);
StartCoroutine(upload_ocr_image(bytes));
if (texture == null)
{
Debug.Log("Couldn't load texture from " + path);
return;
}
// Assign texture to a temporary quad and destroy it after 5 seconds
GameObject quad = GameObject.CreatePrimitive(PrimitiveType.Quad);
quad.transform.position = Camera.main.transform.position + Camera.main.transform.forward * 2.5f;
quad.transform.forward = Camera.main.transform.forward;
quad.transform.localScale = new Vector3(1f, texture.height / (float)texture.width, 1f);
Material material = quad.GetComponent<Renderer>().material;
if (!material.shader.isSupported) // happens when Standard shader is not included in the build
material.shader = Shader.Find("Legacy Shaders/Diffuse");
material.mainTexture = texture;
Destroy(quad, 5f);
// If a procedural texture is not destroyed manually,
// it will only be freed after a scene change
Destroy(texture, 5f);
}
}, maxSize);
Debug.Log("Permission result: " + permission);
}
}
IEnumerator upload_ocr_image(byte[] bytes)
{
// UtilityScript.GetComponent<utility>().Sand_Clock_Loading(true);
// yield return new WaitForSeconds(2.5f);
WWWForm formDate = new WWWForm();
formDate.AddField("frameCount", Time.frameCount.ToString());
formDate.AddBinaryData("ocr_image", bytes, "ocr.jpg", "image/jpg");
formDate.AddField("phone_code", "+61");
formDate.AddField("phone_number", "434599859");
using (UnityWebRequest www = UnityWebRequest.Post(web_url.url_upload_ocr_image, formDate))
{
yield return www.Send();
//UtilityScript.GetComponent<utility>().Sand_Clock_Loading(false);
if (www.isNetworkError)
{
Debug.Log(www.error);
// UtilityScript.GetComponent<utility>().MessageBox_Check_Connection();
}
else
{
Debug.Log(www.downloadHandler.text);
}
}
}
And this the code in server codeigniter php.
function upload_ocr_image()
{
$phone_code = $this->input->post('phone_code', true);
$phone_number = $this->input->post('phone_number', true);
$allowedType = array(IMAGETYPE_GIF,IMAGETYPE_JPEG,IMAGETYPE_PNG);
$imgType = exif_imagetype($_FILES['ocr_image']['tmp_name']);
if(!in_array($imgType,$allowedType))
{
echo "Images Type Error. Images Type Only : GIF , JPEG, PNG";
exit;
}
else
{
//upload original size front end slider
$config['upload_path'] = './assets/ocr_image/';
$config['allowed_types'] = 'gif|jpg|png|jpeg';
$config['file_name'] = $phone_code.$phone_number;
$config['overwrite'] = FALSE;
$config['max_size'] = '8096';
$config['max_width'] = '6000';
$config['max_height'] = '6000';
$this->load->library('upload', $config);
if(!$this->upload->do_upload("ocr_image"))
{
echo "Maximum File Size Only 2 Mb Or Max Width = 2000 , Height = 2000";
exit;
}
else
{
$img_data = $this->upload->data();
// Create Thumbnail
/*
$magicianObj = new imageLib("assets/ocr_image/".$img_data["file_name"].$phone_code.$phone_number);
$magicianObj -> resizeImage(80, 80, 0, true);
$magicianObj -> saveImage("assets/admin/img/photos/".$img_data["raw_name"]."_thumb".$img_data["file_ext"], 100);
$next_id = $next_id.$img_data["file_ext"];
$thumb_name = $img_data["raw_name"]."_thumb".$img_data["file_ext"];
$data = array("photo_name"=>$next_id,
"thumb_photo_name"=>$thumb_name,
"create_date"=>date("Y-m-d H:i:s"));
$this->db->insert("gallery_tbl",$data);
*/
}
}
}
No error found. But it always failed.
This line of code in codeigniter PHP :
if(!$this->upload->do_upload("ocr_image"))
Always return true.
How it work ?, How to upload the picture with proper way ?
Edited :
I use an asset native camera android and ios from unity to take a picture from camera.
Thank You
simply add initialize $this->upload->initialize($config); after
$this->load->library('upload', $config); and check, also check upload directory path is right ? and directory permission
Finally i found the problem.
Just set allowed type extension to except all extension in codeigniter upload file.
change :
$config['allowed_types'] = 'gif|jpg|png|jpeg';
to
$config['allowed_types'] = '*';

C# screen recorder not merging audio

I'm currently trying to make a screen recorder in C#. Right now I have it where the video file and audio files are both successfully made, but I can't figure out how to merge them. This is what I have so far:
public void Stop()
{
int width = bounds.Width;
int height = bounds.Height;
var framRate = 30;
//Save audio:
string audioPath = "save recsound " + outputPath + "\\mic.wav";
record(audioPath, "", 0, 0);
record("close recsound", "", 0, 0);
using (var vFWriter = new VideoFileWriter())
{
//Create new video file:
vFWriter.Open(outputPath + "//video.mp4", width, height, framRate, VideoCodec.MPEG4);
//Make each screenshot into a video frame:
foreach (var imageLocation in inputImageSequence)
{
Bitmap imageFrame = System.Drawing.Image.FromFile(imageLocation) as Bitmap;
vFWriter.WriteVideoFrame(imageFrame);
imageFrame.Dispose();
}
//Add audio:
byte[] audioByte = File.ReadAllBytes(outputPath + "\\mic.wav");
vFWriter.WriteAudioFrame(audioByte);
//Close:
vFWriter.Close();
}
//Delete the screenshots and temporary folder:
DeletePath(tempPath);
}
I don't get any errors, however the audio just isn't being added to the video.mp4. Any help is appreciated!

Unity material rendering using script working incorrectly

This is the hierarchy of Button component.
Button
Image
Text
The script used for rendering is as follows:
for(int ii = 0; ii < idlist.Count; ii++){
GameObject addTypeButton = (GameObject)Instantiate(prefabButton);
addTypeButton.transform.SetParent(ParentPanel, false);
var mybutton = addTypeButton.GetComponent<MyButton>();
//set text
mybutton.text.text = (string)sometext[ii];
//get image
WWW www = new WWW((string)someImageUrl[ii]);
yield return www;
//set image
var b64_bytes = System.Convert.FromBase64String(www.text);
Texture2D tex = new Texture2D(1, 1, TextureFormat.RGB24, false);
tex.EncodeToPNG();
tex.LoadImage(b64_bytes);
//yield return new WaitForSeconds (5) ;
mybutton.image.material.mainTexture = tex;
//testing
File.WriteAllBytes(Application.dataPath + "/../Saved["+ii +"].png", b64_bytes);
}
Testing command generates proper images in the sequence.
However, in Unity the image is rendered on the next object.
Here's the Screenshot
Where exactly I am going wrong?
Don not use WWW.text to load images. This is what WWW.bytes is there for. So, your System.Convert.FromBase64String(www.text); should be removed. You also don't need the Texture2D.EncodeToPNG(); function here since the image you are downloading is already in png or jpeg format. Just save the downloaded image bytes directly.
Finally, if you want your saving stuff to work on every platform, you have to use Application.persistentDataPath instead of Application.dataPath. You should also use Path.Combine to concatenate paths instead of doing it manually.
for (int ii = 0; ii < idlist.Count; ii++)
{
GameObject addTypeButton = (GameObject)Instantiate(prefabButton);
addTypeButton.transform.SetParent(ParentPanel, false);
var mybutton = addTypeButton.GetComponent<MyButton>();
//set text
mybutton.text.text = (string)sometext[ii];
//get image
WWW www = new WWW((string)someImageUrl[ii]);
yield return www;
//set image
byte[] downloadedImage = www.bytes;
Texture2D tex = new Texture2D(1, 1, TextureFormat.RGB24, false);
tex.LoadImage(downloadedImage);
//yield return new WaitForSeconds (5) ;
mybutton.image.material.mainTexture = tex;
//testing
string savePath = Application.persistentDataPath;
savePath = Path.Combine(savePath, "images");
savePath = Path.Combine(savePath, ii.ToString());
savePath = Path.Combine(savePath, ".png");
File.WriteAllBytes(savePath, downloadedImage);
}

generic error occurred in GDI+ saving bitmap to file in a loop witin c#

I'm saving a bitmap to a file on my hard drive inside of a loop (All the jpeg files within a directory are being saved to a database). The save works fine the first pass through the loop, but then gives the subject error on the second pass. I thought perhaps the file was getting locked so I tried generating a unique file name for each pass, and I'm also using Dispose() on the bitmap after the file get saved. Any idea what is causing this error?
Here is my code:
private string fileReducedDimName = #"c:\temp\Photos\test\filePhotoRedDim";
...
foreach (string file in files)
{
int i = 0;
//if the file dimensions are big, scale the file down
Stream photoStream = File.OpenRead(file);
byte[] photoByte = new byte[photoStream.Length];
photoStream.Read(photoByte, 0, System.Convert.ToInt32(photoByte.Length));
Image image = Image.FromStream(new MemoryStream(photoByte));
Bitmap bm = ScaleImage(image);
bm.Save(fileReducedDimName + i.ToString() + ".jpg", ImageFormat.Jpeg);//error occurs here
Array.Clear(photoByte,0, photoByte.Length);
bm.Dispose();
i ++;
}
...
Thanks
Here's the scale image code: (this seems to be working ok)
protected Bitmap ScaleImage(System.Drawing.Image Image)
{
//reduce dimensions of image if appropriate
int destWidth;
int destHeight;
int sourceRes;//resolution of image
int maxDimPix;//largest dimension of image pixels
int maxDimInch;//largest dimension of image inches
Double redFactor;//factor to reduce dimensions by
if (Image.Width > Image.Height)
{
maxDimPix = Image.Width;
}
else
{
maxDimPix = Image.Height;
}
sourceRes = Convert.ToInt32(Image.HorizontalResolution);
maxDimInch = Convert.ToInt32(maxDimPix / sourceRes);
//Assign size red factor based on max dimension of image (inches)
if (maxDimInch >= 17)
{
redFactor = 0.45;
}
else if (maxDimInch < 17 && maxDimInch >= 11)
{
redFactor = 0.65;
}
else if (maxDimInch < 11 && maxDimInch >= 8)
{
redFactor = 0.85;
}
else//smaller than 8" dont reduce dimensions
{
redFactor = 1;
}
destWidth = Convert.ToInt32(Image.Width * redFactor);
destHeight = Convert.ToInt32(Image.Height * redFactor);
Bitmap bm = new Bitmap(destWidth, destHeight,
PixelFormat.Format24bppRgb);
bm.SetResolution(Image.HorizontalResolution, Image.VerticalResolution);
Graphics grPhoto = Graphics.FromImage(bm);
grPhoto.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
grPhoto.DrawImage(Image,
new Rectangle(0, 0, destWidth, destHeight),
new Rectangle(0, 0, Image.Width, Image.Height),
GraphicsUnit.Pixel);
grPhoto.Dispose();
return bm;
}
If I'm reading the code right, your i variable is zero every time through the loop.
It is hard to diagnose exactly what is wrong, I would recommend that you use using statements to ensure that your instances are getting disposed of properly, but it looks like they are.
I originally thought it might be an issue with the ScaleImage. So I tried a different resize function (C# GDI+ Image Resize Function) and it worked, but i is always set to zero at beginning of each loop. Once you move i's initialization outside of the loop your scale method works as well.
private void MethodName()
{
string fileReducedDimName = #"c:\pics";
int i = 0;
foreach (string file in Directory.GetFiles(fileReducedDimName, "*.jpg"))
{
//if the file dimensions are big, scale the file down
using (Image image = Image.FromFile(file))
{
using (Bitmap bm = ScaleImage(image))
{
bm.Save(fileReducedDimName + #"\" + i.ToString() + ".jpg", ImageFormat.Jpeg);//error occurs here
//this is all redundant code - do not need
//Array.Clear(photoByte, 0, photoByte.Length);
//bm.Dispose();
}
}
//ResizeImage(file, 50, 50, fileReducedDimName +#"\" + i.ToString()+".jpg");
i++;
}
}

Display pictures of sd card in GridView

I am trying to display some pictures from the sd storage in GridView in a Xamarin.Android app.
The only documentation I've found is this: http://docs.xamarin.com/recipes/android/data/files/selecting_a_gallery_image
But it only works for one image, opening two or more pictures gives me an Java.Lang.OutOfMemoryError
on this row:
imageView.SetImageURI (bitmapList [position]);
Found some Android answers here on SO:
https://stackoverflow.com/a/823966/511299
Translated to C#:
public static Bitmap DecodeFile (String s)
{
try
{
s = s.Replace ("file://", "");
//Decode image size
BitmapFactory.Options o = new BitmapFactory.Options ();
o.InJustDecodeBounds = true;
BitmapFactory.DecodeStream (new System.IO.FileStream (s, System.IO.FileMode.Open), null, o);
//The new size we want to scale to
int REQUIRED_SIZE = 70;
//Find the correct scale value. It should be the power of 2.
int scale = 1;
while (o.OutWidth/scale/2>=REQUIRED_SIZE && o.OutHeight/scale/2>=REQUIRED_SIZE)
{
scale *= 2;
}
//Decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options ();
o2.InSampleSize = scale;
return BitmapFactory.DecodeStream (new System.IO.FileStream (s, System.IO.FileMode.Open), null, o2);
}
catch (FileNotFoundException e)
{
}
return null;
}
This gives me an
System.IO.IOException: Sharing violation on path storage/sdcard0/Pictures/MyAppPhotos/44cdbcf0-a488-40b8-98a9-79f3dc8d9deb.jpg
on the line of
return BitmapFactory.DecodeStream (new System.IO.FileStream (s, System.IO.FileMode.Open), null, o2);
Is it possible I access the file twice?
Or is it perhaps because I use FileStream instead of FileInputStream. Trying to use BitmapFactory.DecodeStream requires a System.IO.Stream as parameter, opposed to the example requiring a string :(
More detailed, here is the Android version of decodeStream:
public static Bitmap decodeStream (InputStream is, Rect outPadding, BitmapFactory.Options opts)
while this is all I can find for Xamarin.Android:
public static Bitmap DecodeStream (System.IO.Stream is, Rect outPadding, BitmapFactory.Options opts)
Solved it. Used BitmapFactory.DecodeFile(String path, BitmapFactory.Options opts) instead!

Categories

Resources