Making a color picker and learning English
I’m trying to use
csharp* *Application.CaptureScreenshot("Screenshot.png");* *
but i do not understand. Where is this “Screenshot.png” ? where it go? My OS is Windows.
I do not understand if it is saving on disk and where. I’m looking at the assets folder, outside the asset folder and in the build folder but i do not find Screenshot.png.
Also I do not know how to transform this Capture Screenshot into a texture 2D.
tex.LoadImage(Application.dataPath + "/Screenshot.png", bytes);
I know how to pick up the color from a texture using GetPixel . I wish to get the color under the mouse position. Here is the code
```csharp
* // make a screen-shot
Application.CaptureScreenshot(“Screenshot.png”);
// HOW TO: convert the screen-shot to a texture2D ?
Texture2D tex = new Texture2D(2, 2);// Create Texture.Size does not matter.
//LoadImage will replace with incoming image size.
tex.LoadImage(Application.dataPath + "/Screenshot.png", bytes);//do not work
// get the color pixel in the same coordinates of the mouse position
Vector3 mouseCoordinates = Input.mousePosition;
myFinalColor = tex.GetPixel((int)mouseCoordinates.x,(int)mouseCoordinates.y);*</em>
```
A̶c̶c̶o̶r̶d̶i̶n̶g̶ ̶t̶o̶ ̶t̶h̶e̶ ̶s̶c̶r̶i̶p̶t̶i̶n̶g̶ ̶r̶e̶f̶e̶r̶e̶n̶c̶e̶,̶ ̶A̶p̶p̶l̶i̶c̶a̶t̶i̶o̶n̶.̶C̶a̶p̶t̶u̶r̶e̶S̶c̶r̶e̶e̶n̶s̶h̶o̶t̶ ̶u̶s̶e̶s̶ ̶t̶h̶e̶ ̶A̶p̶p̶l̶i̶c̶a̶t̶i̶o̶n̶.̶p̶e̶r̶s̶i̶s̶t̶e̶n̶t̶D̶a̶t̶a̶P̶a̶t̶h̶ ̶f̶i̶l̶e̶ ̶p̶a̶t̶h̶.̶
F̶o̶r̶ ̶w̶i̶n̶d̶o̶w̶s̶ ̶t̶h̶i̶s̶ ̶i̶s̶ ̶u̶s̶u̶a̶l̶l̶y̶ ̶i̶n̶ ̶:̶ ̶C̶:̶\̶U̶s̶e̶r̶s̶\̶<̶u̶s̶e̶r̶_̶n̶a̶m̶e̶>̶\̶A̶p̶p̶D̶a̶t̶a̶\̶L̶o̶c̶a̶l̶L̶o̶w̶\̶<̶c̶o̶m̶p̶a̶n̶y̶_̶n̶a̶m̶e̶>̶\̶<̶p̶r̶o̶d̶u̶c̶t̶_̶n̶a̶m̶e̶>̶
C̶o̶n̶f̶i̶r̶m̶ ̶w̶i̶t̶h̶ ̶a̶ ̶d̶e̶b̶u̶g̶ ̶i̶n̶ ̶a̶ ̶S̶t̶a̶r̶t̶ ̶f̶u̶n̶c̶t̶i̶o̶n̶ ̶:̶ ̶D̶e̶b̶u̶g̶.̶L̶o̶g̶(̶ ̶A̶p̶p̶l̶i̶c̶a̶t̶i̶o̶n̶.̶p̶e̶r̶s̶i̶s̶t̶e̶n̶t̶D̶a̶t̶a̶P̶a̶t̶h̶ ̶)̶;̶
H̶o̶w̶e̶v̶e̶r̶ ̶i̶n̶ ̶m̶y̶ ̶t̶e̶s̶t̶ ̶(̶E̶d̶i̶t̶o̶r̶)̶,̶ ̶t̶h̶e̶ ̶s̶c̶r̶e̶e̶n̶s̶h̶o̶t̶ ̶w̶a̶s̶ ̶s̶a̶v̶e̶d̶ ̶t̶o̶ ̶t̶h̶e̶ ̶r̶o̶o̶t̶ ̶f̶o̶l̶d̶e̶r̶ ̶o̶f̶ ̶t̶h̶e̶ ̶p̶r̶o̶j̶e̶c̶t̶ ̶(̶?̶)̶
Thanks to LeftyRighty. I misread the docs, that state this is for mobile platforms. So to avoid headaches you should specify the file path in the file name
So line 2 and 9 should use Application.persistentDataPath. eg :
Application.CaptureScreenshot( Application.persistentDataPath + “/Screenshot.png” );
Now looking at the scripting reference for Texture2D.LoadImage, it looks like it converts a byte array to a texture, not actually load a texture. So you could try using WWW.LoadImageIntoTexture , or System.IO
For example, here is my test script using System.IO to read the texture data from a file path as bytes, then converting it to a texture with LoadImage :
using UnityEngine;
using System.Collections;
public class GetScreenshot : MonoBehaviour
{
public Renderer planeRenderer;
void Start()
{
Debug.Log( Application.persistentDataPath );
}
void Update()
{
if ( Input.GetMouseButtonDown(0) )
{
Application.CaptureScreenshot( Application.persistentDataPath + "/Screenshot.png" );
Debug.Log( "screenshot saved" );
}
if ( Input.GetMouseButtonDown(1) )
{
Debug.Log( "loading texture" );
string filePath = Application.persistentDataPath + "/Screenshot.png";
if ( !System.IO.File.Exists( filePath ) ) // check if file exists
{
Debug.LogError( filePath + " NOT FOUND..." );
return;
}
byte[] fileData = System.IO.File.ReadAllBytes( filePath );
Texture2D tex = new Texture2D( 2, 2 );
tex.LoadImage( fileData );
planeRenderer.material.mainTexture = tex;
}
}
}
I have also included my test project (Unity 5.2.3f1). Import into a new blank project so there is no accidents
2632069–185028–getscreenshot.unitypackage (32.2 KB)
I think you missed the “For Mobile platforms…” caveat in the docs, to be fair it doesn’t actually say anything about non mobile platforms other than the web player
LeftyRighty : Ah, thank you for clarifying. I did mis-read that, and have edited the post.
AlanMattano : I think RenderTexture may be a more optimal solution for continually updating a texture and reading information from it; rather than saving a screenshot, then loading, then reading. I’ve never used RenderTexture, so am going to play around with it now to see what I can find out.
Nope, nope nope. After experimenting and reading numerous threads, converting a RenderTexture back to a Texture2D just to read one pixel is a convoluted pain in the ****. No to mention the massive lag created by using ReadPixels for a large area every frame, as well as texture.Apply(). Why one cannot just simply access the current texture in the RenderTexture buffer is a mystery to me.
This is the most in-depth discussion I’ve found : Speeding up reading from a RenderTexture - Questions & Answers - Unity Discussions
an interesting idea about using compute shaders to access a render target (which is well beyond my scope) : Unity Bug workaround: ReadPixels() and RenderTexture.antiAliasing > 1 | eVRydayVR
So I made a way that uses good ol ReadPixels, but just using a 1x1 texture and only reading the pixel at the mouse position.
using UnityEngine;
using System.Collections;
public class GetScreenPixel : MonoBehaviour
{
public Renderer planeRenderer;
private Texture2D screenCaptureTexture = null;
private Vector3 mouseCoordinates = Vector3.zero;
void Start()
{
// to avoid the error :
// "ReadPixels was called to read pixels from system frame buffer, while not inside drawing frame."
// ReadPixels must be called AFTER the frame has been rendered
// so process has to be done in a coroutine after waiting for the end of frame
StartCoroutine( "ReadScreenAfterRender" );
}
void Update()
{
// store mouse position
mouseCoordinates = Input.mousePosition;
// check if texture has been rendered
if ( screenCaptureTexture )
{
// get colour
Color myFinalColor = screenCaptureTexture.GetPixel( 0, 0 );
// for testing
planeRenderer.material.color = myFinalColor;
}
}
IEnumerator ReadScreenAfterRender()
{
while ( true )
{
// yield wait until screen has been rendered
yield return new WaitForEndOfFrame();
// create a texture to pass to encoding
// ** only for one pixel to avoid applying a large texture every frame **
Texture2D tex = new Texture2D( 1, 1, TextureFormat.RGB24, false );
// put buffer into texture
// ** only for one pixel at the mouse position **
tex.ReadPixels( new Rect( (int)mouseCoordinates.x, (int)mouseCoordinates.y, (int)mouseCoordinates.x + 1, (int)mouseCoordinates.y + 1 ), 0, 0 );
tex.Apply();
// store in global variable
screenCaptureTexture = tex;
}
}
}
The only problem it has is if the game window is not set to free aspect then it doesn’t factor in the screen offset of the game window
I’ve attached an export of my test (Unity 5.2.3f1). The mouse cursor crosshair object was just to show the mouse position in the screenshots.
2632329–185050–getscreenpixel.unitypackage (28.1 KB)
1 Like
Wonderful help! A Screenshot can capture the final color using the new UI, after rendering all the 3D scene using multiple cameras that renders at the same time, after post process effects are apply and other cameras that renders in background. The Screenshot covers all cases and Yes i do not need it on disk.
[quote=“AlucardJay, post:5, topic: 626966, username:AlucardJay”]
So I made a way that uses good ol ReadPixels, but just using a 1x1 texture and only reading the pixel at the mouse position.
[/quote]
Alucardj, Thanks a lot!
Why you put line 48 in the wile loop? Is in this case better to put it outside on top?
`
~~~
- // create a texture to pass to encoding[/COLOR]
[/COLOR][/FONT][/COLOR][/FONT][/COLOR][/FONT] [FONT=Georgia][COLOR=#0059b3]
[COLOR=rgb(0, 0, 0)][FONT=Georgia][COLOR=#0059b3][FONT=Courier New][COLOR=rgb(0, 0, 0)] Texture2D tex =new Texture2D(1, 1, TextureFormat.RGB24, false);*
~~~
* _
I finish the code and I pass it here.`[/I][/COLOR]_
_```csharp*_
*using UnityEngine;
public enum StateType {
off,
pickingColor
};
public class ColorPickerManager : MonoBehaviour
{
private StateType cursorStage;// To use the state create a variable
private string filePath;
private Texture2D tex;
void Start ()
{
cursorStage = StateType.off;
filePath = Application.persistentDataPath + "/Screenshot.png"; // prepare the full path for the color screen picker.
tex = new Texture2D(2, 2);// Create Texture. Size does not matter, since LoadImage will replace with incoming image size.
}
void Update ()
{
switch (cursorStage)
{
case StateType.off:
break;
case StateType.pickingColor:
PickingColor();
break;
default:
Debug.LogWarning("THERE IS A PROBLEM IN THE STAGE NAME: cursorStage "+
"\n Current stage do not exist");
break;
}
}
#region Start Picking Color function call from color picker button
public void StartPickingColor() {
// Is call only once. For example from outside using the new UI.
// First make a screen-shot and save it into disk
Application.CaptureScreenshot(filePath);
// switch the STATE to a new state
cursorStage = StateType.pickingColor;
}
#endregion
// helpers
public Color myFinalColor;
private Vector3 mouseCoordinates;
private bool pickingColor;
public void PickingColor()
{
#region Picking colors from a SCREEN SHOT
if (Input.GetMouseButtonDown(0)) {
// Find and pick up the mouse position
mouseCoordinates = Input.mousePosition;
pickingColor = true;
if (!System.IO.File.Exists(filePath)) // check if file exists
{
Debug.LogError(filePath + " NOT FOUND...");
return;
}
byte[] fileData = System.IO.File.ReadAllBytes(filePath);
if (!tex.LoadImage(fileData)) // check if load the image from disk
{
Debug.LogError(filePath + "The data can't be loaded");
return;
}
else Debug.Log("The data can be loaded");
}
#endregion
#region Load image and pick the color form mouse screen position
if (pickingColor)
{
if (Input.GetMouseButtonUp(0))
{
pickingColor = false;
// get the color pixel in the same coordinates of the mouse position
myFinalColor = tex.GetPixel((int)mouseCoordinates.x, (int)mouseCoordinates.y);
cursorStage = StateType.off; // switch state
}
}
#endregion
}
}
_```_
_[/FONT]*_