I have made an app that takes pictures of the screen and saves it in Gallery with name i have given using DateTime class and my own prefix. The code on Android works perfect, when you press the button it takes the screenshot and it finishes everything. But the story is not the same on iOS. It crashes whenever the button is pressed. This is the code :
Flash.SetActive(true);
RenderTexture rt = new RenderTexture(resWidth, resHeight, 24);
cam.targetTexture = rt;
Texture2D screenShot = new Texture2D(resWidth, resHeight, TextureFormat.RGB24, false);
cam.Render();
RenderTexture.active = rt;
screenShot.ReadPixels(new Rect(0, 0, resWidth, resHeight), 0, 0);
cam.targetTexture = null;
RenderTexture.active = null;
Destroy(rt);
byte[] bytes = screenShot.EncodeToPNG();
filename = ScreenShotName(resWidth, resHeight);
FullSharePath = "/storage/emulated/0/GarderobaShots/" + filename + ".png";
Texture2D textu = new Texture2D(900,1320, TextureFormat.RGBAFloat, false);
textu.LoadImage(bytes);
textu.Apply();
spr = Sprite.Create(textu ,new Rect(0.0f, 0.0f, textu.width, textu.height), new Vector2(1f, 1f), 100.0f);
ShareAbleObject.transform.GetChild(1).gameObject.GetComponent<Image> ().sprite = spr;
ShareAbleObject.SetActive(true);
NativeGallery.SaveImageToGallery(textu, "AmazingGirlsShots", filename + ".png");
takeHiResShot = false;
Just a quick introduction to code It switches MainCamera of the scene with some camera i have(it's smaller and it has different canvas(only text)) then it activates object i have called Flash which is white flash on screen,it goes off by itself Afterwards it render texture from screen and saves it in
Texture2D textu
Full Share path is the path where this file will be stored so the user wants, he can share it or see it from game
NativeGallery.SaveImageToGallery(textu, "AmazingGirlsShots", filename".png");
It's plugin I took for ios and android that refreshes gallery for an image to be shown in the gallery, otherwise its just somewhere in phone I think that cant be the problem as its check plugin that many people use.
Be sure to set the Permission Privacy Settings in Info.plist.
Related
I'm having this problem with sprites in my Unity3D project. Basiclly I can't change sprite in SpriteRenderer component during runtime. During my research I've only seen solutions that require you to have the sprite pre-loaded, but I can't because it's generated based on the users input image.
So what happens is the user can change the background of the "game" by inputing his own photo from his computer. I get the photo in and everything and I generate a sprite from it, but when I change the base sprite with his sprite, nothing happens. The base sprite is still showing. If I put the background sprite on a panel's Image in canvas, then everything works great, but if I do the same with SpriteRenderer then nothing happens. Here is my code:
public class UploadImage : MonoBehaviour
{
public GameObject background;
public Sprite sp;
[DllImport("__Internal")]
private static extern void ImageUploaderCaptureClick();
public void setTexture(Texture2D texture)
{
sp = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(texture.width / 2, texture.height / 2));
background.GetComponent<SpriteRenderer>().sprite = sp;
}
IEnumerator LoadTexture(string url)
{
WWW image = new WWW(url);
yield return image;
Texture2D texture = new Texture2D(1, 1);
image.LoadImageIntoTexture(texture);
Debug.Log("Loaded image size: " + texture.width + "x" + texture.height);
setTexture(texture);
}
void FileSelected(string url)
{
StartCoroutine(LoadTexture(url));
}
public void OnButtonPointerDown()
{
#if UNITY_EDITOR
string path = UnityEditor.EditorUtility.OpenFilePanel("Open image", "", "jpg,png,bmp");
if (!System.String.IsNullOrEmpty(path))
FileSelected("file:///" + path);
#else
ImageUploaderCaptureClick ();
#endif
}
}
I can't have the background on an image in canvas because other game objects lose transparency and if I set the alpha on image too low, then when game objects move, it leaves everything blurry.
Thanks for your help
I think you are setting the sprites pivot wrong when generating the sprite. Your sprite should even be displayed at the moment but its far away from where you expect it to be.
Change your code to something like this:
sp = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f));
This question already has answers here:
Can I take a photo in Unity using the device's camera?
(8 answers)
Closed 1 year ago.
I am trying to capture what the camera sees in phone in an AR app and take a photo of it. What I found was to take a screenshot of the device and then save that as an image. However, I want to take a screenshot of what the camera sees instead of the screen. That is without any 2D or 3D elements created in the application. Just purely what the camera sees. How do I do this?
public void Start() {
StartCoroutine ("SaveImage");
}
WaitForEndOfFrame frameEnd = new WaitForEndOfFrame ();
IEnumerator SaveImage() {
// Create a texture the size of the screen, RGB24 format
int width = Screen.width;
int height = Screen.height;
yield return frameEnd;
var tex = new Texture2D (width, height, TextureFormat.RGB24, false);
// Read screen contents into the texture
tex.ReadPixels (new Rect (0, 0, width, height), 0, 0);
tex.Apply ();
byte[] bytes = tex.EncodeToPNG ();
Destroy (tex);
var form = new WWWForm ();
form.AddField ("plant", plantComponentID);
form.AddBinaryData ("image", bytes, "screenShot.png", "image/png");
yield return null;
}
Interesting question.
What I would try is to set up a RenderTexture, and tell a camera in your scene to render to it. Then I would try to use the
ImageConversion class to get my camera eye screenshot to a file.
This is just what my attempt would be. Not sure if that is the correct way, so providing that just in case it helps. I would be glad to know the outcome of your attempt in case you try it :)
I have got CamFeed.rendertexture and CamFeed.mat files. Im loading them using my script and setting it up to the camera as target texture and material to another quad respectively but it just shows a black screen.
Material newMat = Resources.Load("CamFeed", typeof(Material)) as Material;
RenderTexture rendertexture = Resources.Load("CamFeed", typeof(Material)) as RenderTexture;
FirstPersonCamera.targetTexture = rendertexture;
quad.GetComponent<Renderer>().material = newMat;
How can I be able to sort it out?
Well, firstly, why are you converting a typeof(Material) into RenderTexture? You should have one of each in your Resources folder, named distinctively, so that you instantiate them the following way:
Material newMat = Resources.Load<Material>("CamFeedMaterial");
RenderTexture rendertexture = Resources.Load<RenderTexture>("CamFeedTexture");
Also make sure that your material uses a shader such as Unlit\Texture, since you are going to need to attach the RenderTexture to it, either in the Editor or from code:
newMat.mainTexture = rendertexture;
Finally, your last bit of code stays the same:
FirstPersonCamera.targetTexture = rendertexture;
quad.GetComponent<Renderer>().material = newMat;
I've been trying to take a screenshot and then immediately after, use it to show some sort of preview and some times it works and some times it doesn't, I'm currently not at work and I don't have unity in this computer so I'll try to recreate it on the fly (there might be some syntax mistakes here and there)
public GameObject screenshotPreview;
public void TakeScreenshot () {
string imageName = "screenshot.png";
// Take the screenshot
ScreenCapture.CaptureScreenshot (imageName);
// Read the data from the file
byte[] data = File.ReadAllBytes(Application.persistentDataPath + "/" + imageName);
// Create the texture
Texture2D screenshotTexture = new Texture2D(Screen.width, Screen.height);
// Load the image
screenshotTexture.LoadImage(data);
// Create a sprite
Sprite screenshotSprite = Sprite.Create (screenshotTexture, new Rect(0, 0, Screen.width, Screen.height), new Vector2(0.5f, 0.5f) );
// Set the sprite to the screenshotPreview
screenshotPreview.GetComponent<Image> ().sprite = screenshotSprite;
}
As far as I've read, ScreenCapture.CaptureScreenshot is not async so the image should have been written right before I try to load the data, but the problem is as I've said before some times it doesn't work and it loads an 8x8 texture with a red question mark, which apparently is the texture failing to be loaded but the file should've been there so I cannot understand why it's not getting loaded properly.
another thing I've tried (which is disgusting but I'm getting tired of this and running out of ideas) is to put in the update method to wait for some time and then execute the code to load the data and create the texture, sprite and display it but even so, it fails some times, less frequently than before but it still fails, which leads me to belive that even if the file was created it hasn't finish beign written, does anyone know a workaround to this? any advice is appreciated.
As extra information this project is being run in an iOS device.
The ScreenCapture.CaptureScreenshot function is known to have many problems. Here is another one of it.
Here is a quote from its doc:
On Android this function returns immediately. The resulting screenshot
is available later.
The iOS behavior is not documented but we can just assume that the behavior is the-same on iOS. Wait for few frames after taking the screenshot before you attempt to read/load it.
public IEnumerator TakeScreenshot()
{
string imageName = "screenshot.png";
// Take the screenshot
ScreenCapture.CaptureScreenshot(imageName);
//Wait for 4 frames
for (int i = 0; i < 5; i++)
{
yield return null;
}
// Read the data from the file
byte[] data = File.ReadAllBytes(Application.persistentDataPath + "/" + imageName);
// Create the texture
Texture2D screenshotTexture = new Texture2D(Screen.width, Screen.height);
// Load the image
screenshotTexture.LoadImage(data);
// Create a sprite
Sprite screenshotSprite = Sprite.Create(screenshotTexture, new Rect(0, 0, Screen.width, Screen.height), new Vector2(0.5f, 0.5f));
// Set the sprite to the screenshotPreview
screenshotPreview.GetComponent<Image>().sprite = screenshotSprite;
}
Note that you must use StartCoroutine(TakeScreenshot()); to call this function.
If that did not work, don't use this function at-all. Here is another way to take and save screenshot in Unity:
IEnumerator captureScreenshot()
{
yield return new WaitForEndOfFrame();
string path = Application.persistentDataPath + "Screenshots/"
+ "_" + screenshotCount + "_" + Screen.width + "X" + Screen.height + "" + ".png";
Texture2D screenImage = new Texture2D(Screen.width, Screen.height);
//Get Image from screen
screenImage.ReadPixels(new Rect(0, 0, Screen.width, Screen.height), 0, 0);
screenImage.Apply();
//Convert to png
byte[] imageBytes = screenImage.EncodeToPNG();
//Save image to file
System.IO.File.WriteAllBytes(path, imageBytes);
}
Programmer's code worked successfully by being called like the following. It is designed as coroutine, so it would not interfere frame rate. Hence it should be called as coroutine. Make sure the CallerObject is inheriting from "MonoBehaviour".
public class CallerObject : MonoBehaviour
{
public void Caller()
{
String imagePath = Application.persistentDataPath + "/image.png";
StartCoroutine(captureScreenshot(imagePath));
}
IEnumerator captureScreenshot(String imagePath)
{
yield return new WaitForEndOfFrame();
//about to save an image capture
Texture2D screenImage = new Texture2D(Screen.width, Screen.height);
//Get Image from screen
screenImage.ReadPixels(new Rect(0, 0, Screen.width, Screen.height), 0, 0);
screenImage.Apply();
Debug.Log(" screenImage.width" + screenImage.width + " texelSize" + screenImage.texelSize);
//Convert to png
byte[] imageBytes = screenImage.EncodeToPNG();
Debug.Log("imagesBytes=" + imageBytes.Length);
//Save image to file
System.IO.File.WriteAllBytes(imagePath, imageBytes);
}
}
I see nothing in the docs that says its not Async. In fact, for Android (if I'm reading this correctly), it explicitly says it's async.
That said, I'd try stalling while the file is not found. Throw it in a coroutine and
FileInfo yourFile = new FileInfo("YourFile.png");
while (File.Exists(yourFile.name) || IsFileLocked(yourFile))
yield return null;
IsFileLocked
You could also try throwing in some debug checks in there to see how long it takes (seconds or frames) before the file appears (assuming it ever appears).
Edit: As derHugo pointed out, the file existing doesn't mean the file is ready yet. I have edited the code to handle that! But it still doesn't cover the case where the file already existed, in which case you probably want a dynamic file name like with a timestamp, or you want to delete the file first!
currently i'm downloading an image from web via WWW. That works perfect for all targeted platforms excepting iOS.
On iOS the image appears just black.
Here is the code:
public void receiveData(WWW receivedData)
{
image.sprite = Sprite.Create(receivedData.texture, new Rect(new Vector2(0,0), new Vector2(50, 50)), new Vector2(0.5f, 0.5f));
image.color = Color.white;
}
I've been trying around for some time now without any results...
F.E. i tried to change the format of the texture with textureFormat or creating a new Texture2D and changed the pixel. But all results in a black image.
Does anyone have an idea what the matter is?
Best Regards
It is likely black because the WWW is not yet finished downloading on iOS. That code should be in a coroutine function and you have to wait with yield return receivedData. If this does not solve your problem, you have to post the rest of your code but this is likely the problem.
public IEnumerator receiveData(WWW receivedData)
{
//Wait to finish downloading image
yield return receivedData;
//You can now create sprite from the data image
image.sprite = Sprite.Create(receivedData.texture, new Rect(new Vector2(0,0), new Vector2(50, 50)), new Vector2(0.5f, 0.5f));
image.color = Color.white;
}
How large is the image? Is it possible you are exceeding the maximum allowed image size for the hardware?