【问题标题】:System.Drawing.Image Parameter Not ValidSystem.Drawing.Image 参数无效
【发布时间】:2016-08-08 12:48:39
【问题描述】:

我知道这个问题已经被问过很多次了...我已经搜索并尝试了所有我能做的事情,但我仍然不确定为什么我会收到“参数无效”异常...

我有一个运行 Windows Server 2012 的 Amazon EC2 实例。在那台机器上,我正在运行 Unity3D (Unity 5)。该 Unity 应用程序通过 TCP 从 EC2 实例向我的本地笔记本电脑发送帧(图像)。我的客户端运行的是 Windows 10,但这并不会带来任何影响。

要获取我的图像数据,我执行以下操作:

byte[] GetScreenData() {
  // Create a texture the size of the screen, RGB24 format
  int width = Screen.width;
  int height = Screen.height;

  RenderTexture rt = new RenderTexture(width, height, 24);

  Texture2D tex = new Texture2D(width, height, TextureFormat.RGB24, false);

  Camera camera = GameObject.Find("Main Camera").GetComponent < Camera > ();
  camera.targetTexture = rt;
  camera.Render();

  RenderTexture.active = rt;

  // Read screen contents into the texture
  tex.ReadPixels(new Rect(0, 0, width, height), 0, 0);
  camera.targetTexture = null;
  RenderTexture.active = null;
  Destroy(rt);

  // Encode texture into JPG
  byte[] bytes = tex.EncodeToJPG();
  Destroy(tex);

  return bytes;
 }

然后我使用FlatBuffers 序列化我的数据:

public static byte[] FlatSerialize(this ServerToClientMessage message) {
  var builder = new FlatBufferBuilder(1);

  //Create an ID
  var MessageId = builder.CreateString(message.MessageId.ToString());

  //Start the vector...
  //Loop over each byte and add it - my god, is there not a better way?
  FlatServerToClientMessage.StartImagebytesVector(builder, message.ImageBytes.Length);
  foreach(var imageByte in message.ImageBytes) {
   builder.AddByte(imageByte);
  }
  var imagebytes = builder.EndVector();

  //Start the FlatServerToClientMessage and add the MessageId and imagebytes
  FlatServerToClientMessage.StartFlatServerToClientMessage(builder);
  FlatServerToClientMessage.AddMessageid(builder, MessageId);
  FlatServerToClientMessage.AddImagebytes(builder, imagebytes);

  //End the FlatServerToClientMessage and finish it...
  var flatMessage = FlatServerToClientMessage.EndFlatServerToClientMessage(builder);
  FlatServerToClientMessage.FinishFlatServerToClientMessageBuffer(builder, flatMessage);

  return builder.SizedByteArray();
 }

接下来,我发送我的数据:

public void SendRaw(byte[] dataToSend) {
  ///We must send the length of the message before sending the actual message
  var sizeInfo = new byte[4]; // = BitConverter.GetBytes(dataToSend.Length);

  //Shift the bytes
  sizeInfo[0] = (byte) dataToSend.Length;
  sizeInfo[1] = (byte)(dataToSend.Length >> 8);
  sizeInfo[2] = (byte)(dataToSend.Length >> 16);
  sizeInfo[3] = (byte)(dataToSend.Length >> 24);

  try {
   var stream = Client.GetStream();

   //Send the length of the data
   stream.Write(sizeInfo, 0, 4);
   //Send the data
   stream.Write(dataToSend, 0, dataToSend.Length);
  } catch (Exception ex) {
   Debug.LogException(ex);
  } finally {
   //raise event to tell system that the client has disconnected and that listening must restart...
  }
 }

回到我的客户端设备上,我正在监听传入的数据,这些数据会反序列化并引发一个事件以提醒系统新图像的到来...

private void Run() {
  try {
   // ShutdownEvent is a ManualResetEvent signaled by
   // Client when its time to close the socket.
   while (!ShutDownEvent.WaitOne(0)) {
    try {
     if (!_stream.DataAvailable) continue;

     //Read the first 4 bytes which represent the size of the message, and convert from byte array to int32
     var sizeinfo = new byte[4];
     _stream.Read(sizeinfo, 0, 4);
     var messageSize = BitConverter.ToInt32(sizeinfo, 0);

     //create a new buffer for the data to be read
     var buffer = new byte[messageSize];

     var read = 0;
     //Continue reading from the stream until we have read all bytes @messageSize
     while (read != messageSize) {
      read += _stream.Read(buffer, read, buffer.Length - read);
     }

     var message = new ServerToClientMessage().FlatDeserialize(buffer);

     //raise data received event
     OnDataReceived(message);

    } catch (IOException ex) {
     // Handle the exception...
    }
   }
  } catch (Exception ex) {
   // Handle the exception...
  } finally {
   _stream.Close();
  }
 }

要反序列化,我执行以下操作:

public static ServerToClientMessage FlatDeserialize(this ServerToClientMessage message, byte[] bytes) {

  var bb = new ByteBuffer(bytes);
  var flatmessage = FlatServerToClientMessage.GetRootAsFlatServerToClientMessage(bb);

  message.MessageId = new Guid(flatmessage.Messageid);
  message.ImageBytes = new byte[flatmessage.ImagebytesLength];

  for (var i = 0; i < flatmessage.ImagebytesLength; i++) {
   message.ImageBytes[i] = flatmessage.GetImagebytes(i);
  }

  return message;
 }

为清楚起见,这里是ServerToClientMessage 类:

public class ServerToClientMessage : EventArgs
{
    public Guid MessageId { get; set; }
    public byte[] ImageBytes { get; set; }
}

无论如何,接下来会引发OnDataReceived 事件,然后调用一个函数将ImageBytes 数组转换为System.Drawing.Image。该功能在这里:

public Image byteArrayToImage(byte[] byteArrayIn) {
  // SAME PROBLEM! 
  //var converter = new System.Drawing.ImageConverter();
  // return (Image)converter.ConvertFrom(byteArrayIn); ;

  using(var memoryStream = new MemoryStream(byteArrayIn)) {
   return Image.FromStream(memoryStream, false, false);
  }
 }

现在,我从服务器发送的图像数据很好,而且很漂亮……我已经验证过了。当我使用 JSON 时,这一切都很好。我尝试了很多方法将字节数组转换为图像,但我似乎总是得到Parameter is not valid 异常。我还尝试以不同格式(如 JPG 和 PNG)以及原始像素数据发送我的图像。

有人有想法吗?

【问题讨论】:

    标签: c# image unity3d


    【解决方案1】:

    想通了。

    事实证明,数据是向后的……由于 FlatBuffers 序列化。 解决方法是在序列化过程中颠倒我的for-loop的顺序:

    for (var i = message.ImageBytes.Length; i -->0;)
    {
        builder.AddByte(message.ImageBytes[i]);
    }
    

    【讨论】:

      猜你喜欢
      • 2010-10-12
      • 2012-08-05
      • 2013-09-18
      • 2016-07-07
      • 2022-01-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多