9

I want to make user able to decode the QR image loaded from the gallery, I have found a plugin to explore and load the image as a texture2D, but to decode that QR code, the Texture2D has to be readable/writable, And I checked the plugin, for Android it's doing the exploring and loading stuff with a jar and in IOS platform it's using a packaged library, so I have no access to the code of the lib,

I have searched for the answer, the most solution was to change the importing setting of texture in the Unity inspector, but since this is a texture loaded by code, there is not an inspector setting available for that, So my question is:

Is there any way to make this loaded texture read/writeable by code? without having to access the lib code?

Thanks

Here is the code that could get the texture by this plugin

void OnImageLoad(string imgPath, Texture2D tex, ImageAndVideoPicker.ImageOrientation imgOrientation)
{
    Debug.Log("Image Location : " + imgPath);
    Debug.Log("Image Loaded : " + imgPath);
    texture = tex;
    Texture2D readableText = new Texture2D(tex.width, tex.height);
    readableText.LoadImage(tex.GetRawTextureData());

    string url = QRCodeDecodeController.DecodeByStaticPic(readableText);
    StartCoroutine(GetSceneAndLoadLevel(url));
}

As you can see, I have tried this answer But got no luck.

And here is the error that showed by Android:

06-23 21:47:32.853: I/Unity(10557): (Filename: D Line: 0)
06-23 21:47:33.784: E/Unity(10557): Texture needs to be marked as Read/Write to be able to GetRawTextureData in player
06-23 21:47:33.784: E/Unity(10557): UnityEngine.Texture2D:GetRawTextureData()
06-23 21:47:33.784: E/Unity(10557): TestQR:OnImageLoad(String, Texture2D, ImageOrientation) (at D:\Unity Projects\nnkp\Assets\Scripts\QR\TestQR.cs:123)
06-23 21:47:33.784: E/Unity(10557): <LoadImage>c__Iterator0:MoveNext()
06-23 21:47:33.784: E/Unity(10557): UnityEngine.SetupCoroutine:InvokeMoveNext(IEnumerator, IntPtr) (at /Users/builduser/buildslave/unity/build/Runtime/Export/Coroutines.cs:17)
06-23 21:47:33.784: E/Unity(10557): [./artifacts/generated/common/runtime/TextureBindings.gen.cpp line 512] 

Note:

The source Texture2D is coming from a plugin, I can't set it to Read/Write Enabled from the Editor or use the Editor's TextureImporter.isReadable variable.

Programmer
  • 121,791
  • 22
  • 236
  • 328
armnotstrong
  • 8,605
  • 16
  • 65
  • 130

1 Answers1

31

There are two ways to do this:

1.Use RenderTexture (Recommended):

Use RenderTexture. Put the source Texture2D into RenderTexture with Graphics.Blit then use Texture2D.ReadPixels to read the image from RenderTexture into the new Texture2D.

Texture2D duplicateTexture(Texture2D source)
{
    RenderTexture renderTex = RenderTexture.GetTemporary(
                source.width,
                source.height,
                0,
                RenderTextureFormat.Default,
                RenderTextureReadWrite.Linear);

    Graphics.Blit(source, renderTex);
    RenderTexture previous = RenderTexture.active;
    RenderTexture.active = renderTex;
    Texture2D readableText = new Texture2D(source.width, source.height);
    readableText.ReadPixels(new Rect(0, 0, renderTex.width, renderTex.height), 0, 0);
    readableText.Apply();
    RenderTexture.active = previous;
    RenderTexture.ReleaseTemporary(renderTex);
    return readableText;
}

Usage:

Texture2D copy = duplicateTexture(sourceTextFromPlugin);

This should work and should not throw any error.


2.Use Texture2D.GetRawTextureData() + Texture2D.LoadRawTextureData():

You can't use GetPixels32() because the Texture2D is not readable. You were so close about using GetRawTextureData().

You failed when you used Texture2D.LoadImage() to load from GetRawTextureData().

Texture2D.LoadImage() is only used to load PNG/JPG array bytes not Texture2D array byte.

If you read with Texture2D.GetRawTextureData(), you must write with Texture2D.LoadRawTextureData() not Texture2D.LoadImage().

Texture2D duplicateTexture(Texture2D source)
{
    byte[] pix = source.GetRawTextureData();
    Texture2D readableText = new Texture2D(source.width, source.height, source.format, false);
    readableText.LoadRawTextureData(pix);
    readableText.Apply();
    return readableText;
}

There will be no error with the code above in the Editor but there should be an error in standalone build. Besides, it should still work even with the error in the standalone build. I think that error is more like a warning.

I recommend you use method #1 to do this as it will not throw any error.

Programmer
  • 121,791
  • 22
  • 236
  • 328
  • Hi. still got `06-24 16:27:31.295: E/Unity(19300): Texture needs to be marked as Read/Write to be able to GetRawTextureData in player` error with the line of `byte[] pix = source.GetRawTextureData();` – armnotstrong Jun 24 '17 at 08:30
  • Check my updated answer. I think you should re-read my answer. Use #1 so that you won't get error. – Programmer Jun 24 '17 at 10:53
  • Hi, @Programmer, trying the first method was the first thing I got up from bed :D and it works! thanks for saving my day... Again! And I found it very hard to understand the mechanism of Unity's texture2D, have been struggling for this kind of problem for at least 2 times, especially about the read/write stuff, if may I ask to throw me some more material to read on? :D thanks! thanks! – armnotstrong Jun 25 '17 at 02:43
  • You are welcome. What exactly about`Texture2D` do you not understand? – Programmer Jun 25 '17 at 03:02
  • 1
    By making it unreadable, it becomes very very fast. Making it readable comes at a cost of memory and performance. The reason for this is because making it unreadable will make the texture on the GPU. If you make it readable, the CPU can also access it making the operation slow. GPU is extremely fast. That's the thing. I think you should study "Compute shader" in Unity. You will see how fast you can do stuff with it just because it's running on the GPU instead of CPU. Note that this is an advanced topic. It's similar to making Texture2D unreadable. – Programmer Jun 25 '17 at 04:51
  • Hi, I have fallow first procedure for making texture2d as readable. It's working fine but quality of image will be loose. How can we get original image without loosing quality. – sahithi Jul 11 '18 at 12:51
  • 1
    @sahithi You should probably try the solution 2 if the first one has issues – Programmer Jul 12 '18 at 02:11
  • 1
    Awesome! 1 solution is working like a charm. You are my hero :D – Skylin R Oct 25 '19 at 11:45
  • I included the first method into my project, and it leads to "applicationDidReceiveMemoryWarning" on iPhone and an app crash. – Boris Dec 21 '20 at 12:29
  • for exr loaded at runtime, Texture2D.GetRawTextureData() works but it throws for other formats e.g. Texture2D.GetRawTextureData() ->UnityException: Texture 'xxx' is not readable, the texture memory can not be accessed from scripts. You can make the texture readable in the Texture Import Settings. – Sergio Solorzano Jan 28 '22 at 12:56