从流中获取位图:有bug吗?

4
我有一个比较奇怪的错误。我需要将图像缩小,降低质量并转换为JPEG格式。当我将文件保存在磁盘上时,这一切都能正常工作,但是当我将其保存到流中时,就会出现问题。
System.Drawing.Bitmap bitmap = // valid Bitmap from Disk
System.IO.Stream stream = new MemoryStream();

// JPEG Encoding

System.Drawing.Imaging.ImageCodecInfo jpgEncoder = GetEncoder( System.Drawing.Imaging.ImageFormat.Jpeg );
System.Drawing.Imaging.Encoder encoder2 = System.Drawing.Imaging.Encoder.Quality;
System.Drawing.Imaging.EncoderParameters parameters = new System.Drawing.Imaging.EncoderParameters( 1 );
System.Drawing.Imaging.EncoderParameter parameter = new System.Drawing.Imaging.EncoderParameter( encoder2, qualityLevel );
parameters.Param[0] = parameter;

// Save downscaled on Disk and stream

bitmap.Save( stream, jpgEncoder, parameters );
bitmap.Save( @"C:\TestJPEG.jpg", jpgEncoder, parameters );

// some stream stuff

var bytes = ((MemoryStream)stream).ToArray();
System.IO.Stream inputStream = new MemoryStream( bytes );

// Load from disk and stream

Bitmap fromDisk = new Bitmap( @"C:\TestJPEG.jpg" ); // works
Bitmap fromStream = new Bitmap( inputStream ); // crash invalid parameter no inner message or description
Bitmap fromStream2 = (Bitmap)Bitmap.FromStream( inputStream ); // same error here
// also crashes if I load the "stream" named Stream

我还可以使用Paint打开转换后的文件。有什么建议吗?

编辑: 我正在使用Windows 7专业版上的.Net Framework 4.0。

编辑2: 尝试了那个"Seek"的方法(答案已删除)。

stream.Seek( 0, SeekOrigin.Begin );

它可以使用“旧”流。但我需要从字节数组中加载它。仍然崩溃。


1
你尝试过使用Image.FromStream而不是Bitmap构造函数吗?另外,在文件保存后,如果你Dispose bitmap会发生什么? - leppie
1
你的代码对我有效。我在LINQPad中执行了以下操作,没有异常:http://pastebin.com/Qqz8mXUv。你确定你展示了所有相关部分的代码吗?`GetEncoder`到底是做什么的?`qualityLevel`的值是多少?也许你可以上传你的图片? - Daniel Hilgarth
1
顺便说一句:在尝试运行您的代码时,我在保存位图的那一行遇到了“无效参数”异常。问题出在我传递给new EncoderParameter的值上。您确定您遇到的异常是在您所说的那一行吗? - Daniel Hilgarth
1
@ArndtBieberstein:哈哈,好的。尝试使用您的代码,并将qualityLevel更改为long - Daniel Hilgarth
1
@DanielHilgarth 哇,那真是缺失的拼图。我知道这个函数需要一个 long 值参数,但我没想到那可能是原因。非常好的提示! - Arndt Bieberstein
显示剩余10条评论
1个回答

2
以下代码对我有效:
```html

以下代码对我有效:

```
var bitmap = new Bitmap(@"c:\Dokumente und Einstellungen\daniel.hilgarth\Desktop\Unbenannt.bmp");

ImageCodecInfo jpgEncoder = ImageCodecInfo.GetImageEncoders().Single(x => x.FormatDescription == "JPEG");
Encoder encoder2 = System.Drawing.Imaging.Encoder.Quality;
EncoderParameters parameters = new System.Drawing.Imaging.EncoderParameters( 1 );
EncoderParameter parameter = new EncoderParameter( encoder2, 50L );
parameters.Param[0] = parameter;

System.IO.Stream stream = new MemoryStream();
bitmap.Save( stream, jpgEncoder, parameters );
bitmap.Save(@"C:\Temp\TestJPEG.jpg", jpgEncoder, parameters);

var bytes = ((MemoryStream)stream).ToArray();
System.IO.Stream inputStream = new MemoryStream(bytes);
Bitmap fromDisk = new Bitmap(@"C:\Temp\TestJPEG.jpg");
Bitmap fromStream = new Bitmap(inputStream);

你的代码有一些区别,导致问题的原因可能是其中一个,我猜测:

  • 我使用了50L作为qualityLevel。当使用1250100时,我会收到一个ArgumentException“参数无效”。由于我不知道你的qualityLevel变量的类型或值,这很可能就是问题所在。
  • 我替换了你的GetEncoder方法。我不知道你的方法具体做什么,所以它可能是问题所在,但我怀疑这一点。

我猜 qualityLevel 需要是一个64位整数,也就是 long(或 ulong)。这就导致了问题。 - leppie
1
@leppie:是的,我也这么认为。有趣的是,这个构造函数还接受byteshort值。当传递与byteshort相同的确切值时,它会导致异常。在我看来,这是一个设计不良的API。 - Daniel Hilgarth
GetEncoder 基本上与 ImageCodecInfo.GetImageEncoders().Single(x => x.FormatDescription == "JPEG"); 做的事情相同。 - Arndt Bieberstein
1
查看EncoderParameter的反编译结果,发现这是一个非常奇怪的类。在这里使用的构造函数(接受一个long参数)在转换为int之前没有先检查它是否适合!我只能假设这是作为对现有GDI+代码最薄弱的包装而编写的... - AakashM

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接