winforms
winforms copied to clipboard
System.Drawing.Image.FromStream(...) throws "Parameter is not valid." when Stream.Read does not return full file length
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:
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