winforms icon indicating copy to clipboard operation
winforms copied to clipboard

System.Drawing.Image.FromStream(...) throws "Parameter is not valid." when Stream.Read does not return full file length

Open jesperhoy opened this issue 2 months ago • 0 comments

This happens when Image.FromStream(...) calls Stream.Read(buffer, offset, count) - where count is the full length of the image file (it calls it a number of times first with a smaller count value) - and less than count is returned.

This is a problem with any seekable Stream implementation that "chunks" reads - like downloading large file in multiple parts...

Sample code:

var file = new System.IO.File.OpenRead("C:\\test.png");
// No problem:
var img = System.Drawing.Image.FromStream(file);

var file2 = new System.IO.File.OpenRead("C:\\test.png");
var strm = new MyStream(file2);
// will throw Exception "Parameter is not valid."
var img2 = System.Drawing.Image.FromStream(strm);

Console.WriteLine("Won't reach this line");

// Custom Stream to simulate .Read returning less than full count
class MyStream(System.IO.Stream src) : System.IO.Stream {
  public override bool CanRead => true;
  public override bool CanSeek => true;
  public override bool CanWrite =>false ;
  public override long Length => src.Length;
  public override long Position { get => src.Position; set => src.Position=value; }
  public override void Flush() => throw new NotImplementedException();
  public override long Seek(long offset, SeekOrigin origin) => src.Seek(offset, origin);
  public override void SetLength(long value) => throw new NotImplementedException();
  public override void Write(byte[] buffer, int offset, int count) =>  throw new NotImplementedException();

  // IMPORTANT PART:
  const int ChunkSize = 128 * 1024;
  public override int Read(byte[] buffer, int offset, int count) {
    if (count > ChunkSize) count = ChunkSize;
    return src.Read(buffer, offset, count);
  }
}

Test image: Image

Possibly related to https://github.com/dotnet/winforms/issues/8824

Using System.Drawing.Common nuget package v. 10.0.0

Proposed solution (not aware of implementation): Use Stream.ReadExact instead of Stream.Read

jesperhoy avatar Nov 19 '25 15:11 jesperhoy