Serialize Image

I want to spawn a RawImage over the network.
I've added this script to a prefab to be spawned:
[RequireComponent(typeof(PhotonView))]
public class exchange_frame : MonoBehaviour {

    [SerializeField]
    public RawImage rawImage;

    void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
    {
        if (stream.isWriting)
        {
            stream.SendNext(rawImage);
        }
        else
        {
            rawImage = (RawImage)stream.ReceiveNext();
        }
    }
}
But I received the following:
Exception: cannot serialize(): UnityEngine.UI.RawImage

Should I convert to byte[] ? Or what else?

Comments

  • Hi @StyleMaster,

    you can either convert the RawImage to a byte array (byte arrays are supported by PUN out of the box) or register a custom type to directly use this type in OnPhotonSerializeView. You can read about Custom Types on this guide and follow the example which shows how Vector2 is supported by PUN.

    Is this RawImage changed a lot so that it requires you to use OnPhotonSerializeView? If you just want to send this like once each ten minutes, you might want to take a look at RaiseEvent function and use this for sending because OnPhotonSerializeView is called 20 times a second (default settings) which would result in a lot of used bandwidth and messages.
  • Unfortunatly yes.
    My application has this scenario:
    - Master client spawn the texture over the network.
    - Non-master client get frames from camera and show them on a texture.
    Right now I´ve developed the following code. The texture appears on both but the master client seems to don´t receive the updated texture....

    Master client code:
    public class exchange_frame : MonoBehaviour {
    public RawImage rawImage;
    private Texture2D tex;
    [SerializeField]
    private byte[] rawData;
    void Update()
    {
    if (rawData.Length > 0)
    {
    tex.LoadImage(rawData);
    rawImage.material.mainTexture = tex;
    rawImage.texture = tex;
    }
    }

    void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
    {
    if (stream.isWriting)
    { }
    else
    {
    rawData = (byte[])stream.ReceiveNext();
    }
    }
    }

    Non-Master client code:
    public RawImage rawImage;
    private Texture2D tex;
    private GameObject backgroundCam;
    private RawImage streamCam;
    [SerializeField]
    private byte[] rawData;
    void Start()
    {
    backgroundCam = GameObject.FindGameObjectWithTag("cameraBackground");
    streamCam = (RawImage)backgroundCam.GetComponent();
    }

    void Update()
    {
    rawImage = streamCam;
    Texture2D tex = (Texture2D) streamCam.texture;
    rawData = tex.EncodeToPNG();
    }

    void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
    {
    if (stream.isWriting)
    {
    stream.SendNext(rawData);
    }
    else
    {
    }
    }
  • The application is getting really slow since I´ve added this code, so I think that is really sending data in some way over the network but for some reasons are not received on the master client
  • StyleMaster
    edited June 2017
    Master client (spawn the object and receive bytes):
    [RequireComponent(typeof(PhotonView))]
    public class exchange_frame : MonoBehaviour {
        public RawImage rawImage;
        private Texture2D tex;
    
        [SerializeField]
        private byte[] rawData;
        void Update()
        {
            if (rawData.Length > 0)
            {
                tex.LoadImage(rawData);
                rawImage.material.mainTexture = tex;
                rawImage.texture = tex;
            }
        }
    
        void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
        {
            if (stream.isWriting)
            {
            }
            else
            {
                rawData = (byte[])stream.ReceiveNext();
                
            }
        }
    }


    Non Master client (send bytes):

    [RequireComponent(typeof(PhotonView))]
    public class exchange_frame : MonoBehaviour { 
        public RawImage rawImage;
        private Texture2D tex;
        private GameObject backgroundCam;
        private RawImage streamCam;
    
        [SerializeField]
        private byte[] rawData;
        void Start()
        {
            backgroundCam = GameObject.FindGameObjectWithTag("cameraBackground");
            streamCam = (RawImage)backgroundCam.GetComponent<RawImage>();
            
        }
        void Update()
        {
            rawImage = streamCam;
            Texture2D tex = (Texture2D) streamCam.texture;
            rawData = tex.EncodeToPNG();
        }
    
        void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
        {
            if (stream.isWriting)
            {
                stream.SendNext(rawData);
            }
            else
            {
            }
        }
    }
  • [Deleted User]
    edited June 2017
    You don't need two separate scripts for this. You need to network instantiate an object which has an attached PhotonView component which furthermore observes an attached scripts with OnPhotonSerializeView function where you have both cases: stream.isWriting and stream.isReading. Also the RawImage component needs to be attached to this game object.
  • So the Non-Master client should only load the prefab from resources and change texture? (without send it in OnPhotonSerializeView)?
  • Whoever should send the data needs to network instantiate this game object (PhotonNetwork.Instantiate(...) function). This way the object gets instantiated on each other client as well, but only the owner writes data to the stream, everyone else is just reading from the stream. In your case only the non-MasterClient(s) should instantiate these objects. However this only works for two clients and need to be extended for more than two clients, if you want to support that.
  • Tried right now: "Client is not the MasterClient in this room" .. it can´t instantiate gameobject if it is not the masterclient
  • Do you use PhotonNetwork.Instantiate or PhotonNetwork.InstantiateSceneObject? The second one can only be called by the MasterClient.
  • I changed to Instantiate.
    Now I have some problems converting the Texture2D into byte[].
    This part:

    Texture2D tex = (Texture2D) streamCam.texture;
    rawData = tex.EncodeToPNG();

    Give me an "invalid cast" error.
    If I change to :

    tex = rawImage.texture as Texture2D;

    I have no errors but the texture is empty, so nothing to show .

    I have to precise that the Texture I´m sending comes from a webcam.
    Any suggestions?