为什么将图像写入流会得到与直接保存到文件不同的结果?

Why does writing an image to a stream give me a different result than directly saving to a file?

我正在尝试向现有图像添加一些矩形。使用以下代码时,一切正常:

var bytes = File.ReadAllBytes("myPath\input.jpg");
var stream = new MemoryStream(bytes);

using (var i = new Bitmap(stream))
{
    using (var graphics = Graphics.FromImage(i))
    {
        var selPen = new Pen(Color.Blue);
        graphics.DrawRectangle(selPen, 10, 10, 50, 50);

        i.Save("myPath\output.jpg", ImageFormat.Jpeg);
    }
}

但是将图像保存到同一个 MemoryStream,然后将所有字节写入一个文件,我得到了一个几乎只有灰色的图像。

这不起作用:

var bytes = File.ReadAllBytes("myPath\input.jpg");
var stream = new MemoryStream(bytes);

using (var i = new Bitmap(stream))
{
    using (var graphics = Graphics.FromImage(i))
    {
        var selPen = new Pen(Color.Blue);
        graphics.DrawRectangle(selPen, 10, 10, 50, 50);

        i.Save(stream, ImageFormat.Jpeg);
    }
}

File.WriteAllBytes("myPath\output.jpg", stream.ToArray());

(错误的)图像如下所示:

如您所见,只有部分图像是灰色的。实际图像的某些部分(白色部分)仍然可见。

为什么会这样,正确的解决方法是什么?

谢谢!

你在第二个例子中重复写入了 Stream;它仍然包含 原始 数据,然后您使用 Save 附加 更多数据。 Stream 像录像带一样工作(有点)。如果你想覆盖流,你需要非常小心地做(并且:并不是所有的流都支持这个概念——想想 "network stream"、"encryption stream" 等)。请注意,ToArray(以及 GetBuffer / TryGetBuffer 方法)会看到 所有 数据,而不仅仅是您认为的 "new" 数据(一个根本不存在的概念,真的 - 就像录像带,你只有 "current" 位置和长度 - 如果你需要知道第一个节目在哪里结束,第二个节目在哪里开始,您需要自己注意,手动)。在这种情况下,添加:

stream.Position = 0; // rewind
stream.SetLength(0); // truncate (important in case the new data is *shorter* than the old)

在阅读之后 Save 之前应该修复它。

您正在将图像从字节数组保存到已初始化的流中。

创建一个新流并保存到其中。

 var stream2 = new MemoryStream();
 i.Save(stream2, ImageFormat.Jpeg);

或者干脆重置上一个

 memoryStream = new MemoryStream(stream.Capacity());