来自 Stream returns 1x1px 的 BitmapImage 而不是整个图像
BitmapImage from Stream returns 1x1px instead of the whole image
我有一个方法可以打开 FileStream
并创建 BitmapImage
,方法是使用 StreamSource
属性.
不知何故,在一台机器上,尝试打开大图像 (6000x4000px) 导致该方法返回 1x1px 图像。
起初我以为图片是从本地网络上的共享文件夹加载的,但它存储在同一台计算机的下载文件夹中。
我看到图片是 "blocked/locked" by Windows 因为它是从未经验证的来源下载的,所以我打开属性并解锁了它。再次尝试加载图片出现同样的问题。
图像已完全下载。
背景资料:
出现问题的机器:
- Windows 7 SP1.
- 32 位。
- 网络框架 4.6.2.
- 4GB 内存,正在使用 2.5GB。
我的机器(按预期工作):
- Windows 10,构建 15063.413。
- 64 位。
- 网络框架 4.7.
- 8GB 内存,已使用 6GB。
代码:
public static BitmapSource SourceFrom(this string fileSource, int? size = null)
{
using (var stream = new FileStream(fileSource, FileMode.Open, FileAccess.Read))
{
var bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
if (size.HasValue)
{
//It's not possible to get the size of image while opening, so get from another place.
var refSize = fileSource.ScaledSize(); //Gets the size of the image.
if (refSize.Height > refSize.Width)
bitmapImage.DecodePixelHeight = size.Value;
else
bitmapImage.DecodePixelWidth = size.Value;
}
bitmapImage.StreamSource = stream;
bitmapImage.EndInit();
bitmapImage.Freeze(); //Just in case you want to load the image in another thread.
return bitmapImage;
}
}
用法:
var image = "C:\Image.jpg".SourceFrom(); //Without any other parameter.
问题:
- 有没有我的代码处理不当的情况,至少这解释了为什么我得到的是 1x1 像素的图像而不是完整尺寸的图像?
- 此外,如果无法加载图像,为什么它不抛出
Exception
?
可能的答案:
- 我的代码不处理图像是否完成下载,但图像已完全下载,所以我不确定是否是这种情况。 I've found a similar thread about the same problem.
工作代码:
using (var stream = new FileStream(fileSource, FileMode.Open, FileAccess.Read))
{
using (var memory = new MemoryStream())
{
stream.CopyTo(memory);
memory.Position = 0;
//...
只需替换这部分代码,并在设置 StreamSource
对象时使用 memory
变量而不是 stream
。
好像是当图片文件很大,或者由于某些其他原因不能立即读取源流时,你必须将源流复制到一个中间的MemoryStream,并将其分配给StreamSource
属性 BitmapImage:
using (var fileStream = new FileStream(fileSource, FileMode.Open, FileAccess.Read))
using (var memoryStream = new MemoryStream())
{
fileStream.CopyTo(memoryStream);
memoryStream.Position = 0;
var bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.CacheOption = BitmapCacheOption.OnLoad
bitmapImage.StreamSource = memoryStream;
bitmapImage.EndInit();
bitmapImage.Freeze();
return bitmapImage;
}
我遇到了同样的问题,CacheOption 不在您代码中的正确位置!!只需在 endInit() 之前添加它;
source.CacheOption = BitmapCacheOption.OnLoad;
像这样 ->
BitmapImage source = new BitmapImage();
source.BeginInit();
source.CacheOption = BitmapCacheOption.OnLoad;
source.StreamSource = fs;
source.EndInit();
当图像解码失败时,BitmapImage
会创建一个 1x1px 的默认图像。您需要注册 DecodeFailed
事件才能检测到这一点。
Exception decodeEx = null;
using (var fileStream = new FileStream(fileSource, FileMode.Open, FileAccess.Read))
{
var bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.StreamSource = fileStream;
bitmapImage.DecodeFailed += (_, e) => decodeEx = e.ErrorException;
bitmapImage.EndInit();
if (decodeEx != null)
throw decodeEx;
bitmapImage.Freeze();
return bitmapImage;
}
在我的例子中,结果是 OutOfMemoryException
。事实上,只有当内存使用率很高并且 BitmapImage
(使用非托管内存)实际调用的本机函数可能无法分配足够的内存时,解码才会失败。
我有一个方法可以打开 FileStream
并创建 BitmapImage
,方法是使用 StreamSource
属性.
不知何故,在一台机器上,尝试打开大图像 (6000x4000px) 导致该方法返回 1x1px 图像。
起初我以为图片是从本地网络上的共享文件夹加载的,但它存储在同一台计算机的下载文件夹中。
我看到图片是 "blocked/locked" by Windows 因为它是从未经验证的来源下载的,所以我打开属性并解锁了它。再次尝试加载图片出现同样的问题。
图像已完全下载。
背景资料:
出现问题的机器:
- Windows 7 SP1.
- 32 位。
- 网络框架 4.6.2.
- 4GB 内存,正在使用 2.5GB。
我的机器(按预期工作):
- Windows 10,构建 15063.413。
- 64 位。
- 网络框架 4.7.
- 8GB 内存,已使用 6GB。
代码:
public static BitmapSource SourceFrom(this string fileSource, int? size = null)
{
using (var stream = new FileStream(fileSource, FileMode.Open, FileAccess.Read))
{
var bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
if (size.HasValue)
{
//It's not possible to get the size of image while opening, so get from another place.
var refSize = fileSource.ScaledSize(); //Gets the size of the image.
if (refSize.Height > refSize.Width)
bitmapImage.DecodePixelHeight = size.Value;
else
bitmapImage.DecodePixelWidth = size.Value;
}
bitmapImage.StreamSource = stream;
bitmapImage.EndInit();
bitmapImage.Freeze(); //Just in case you want to load the image in another thread.
return bitmapImage;
}
}
用法:
var image = "C:\Image.jpg".SourceFrom(); //Without any other parameter.
问题:
- 有没有我的代码处理不当的情况,至少这解释了为什么我得到的是 1x1 像素的图像而不是完整尺寸的图像?
- 此外,如果无法加载图像,为什么它不抛出
Exception
?
可能的答案:
- 我的代码不处理图像是否完成下载,但图像已完全下载,所以我不确定是否是这种情况。 I've found a similar thread about the same problem.
工作代码:
using (var stream = new FileStream(fileSource, FileMode.Open, FileAccess.Read))
{
using (var memory = new MemoryStream())
{
stream.CopyTo(memory);
memory.Position = 0;
//...
只需替换这部分代码,并在设置 StreamSource
对象时使用 memory
变量而不是 stream
。
好像是当图片文件很大,或者由于某些其他原因不能立即读取源流时,你必须将源流复制到一个中间的MemoryStream,并将其分配给StreamSource
属性 BitmapImage:
using (var fileStream = new FileStream(fileSource, FileMode.Open, FileAccess.Read))
using (var memoryStream = new MemoryStream())
{
fileStream.CopyTo(memoryStream);
memoryStream.Position = 0;
var bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.CacheOption = BitmapCacheOption.OnLoad
bitmapImage.StreamSource = memoryStream;
bitmapImage.EndInit();
bitmapImage.Freeze();
return bitmapImage;
}
我遇到了同样的问题,CacheOption 不在您代码中的正确位置!!只需在 endInit() 之前添加它;
source.CacheOption = BitmapCacheOption.OnLoad;
像这样 ->
BitmapImage source = new BitmapImage();
source.BeginInit();
source.CacheOption = BitmapCacheOption.OnLoad;
source.StreamSource = fs;
source.EndInit();
当图像解码失败时,BitmapImage
会创建一个 1x1px 的默认图像。您需要注册 DecodeFailed
事件才能检测到这一点。
Exception decodeEx = null;
using (var fileStream = new FileStream(fileSource, FileMode.Open, FileAccess.Read))
{
var bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.StreamSource = fileStream;
bitmapImage.DecodeFailed += (_, e) => decodeEx = e.ErrorException;
bitmapImage.EndInit();
if (decodeEx != null)
throw decodeEx;
bitmapImage.Freeze();
return bitmapImage;
}
在我的例子中,结果是 OutOfMemoryException
。事实上,只有当内存使用率很高并且 BitmapImage
(使用非托管内存)实际调用的本机函数可能无法分配足够的内存时,解码才会失败。