MrC*_*uer 38 c# image file picturebox
我有一个PictureBox的图像指向某个文件"A".在执行时我想将PictureBox的图像更改为另一个"B"但我收到以下错误:
"mscorlib.dll中出现'System.IO.IOException'类型的第一次机会异常附加信息:进程无法访问文件"A",因为它正由另一个进程使用."
我将Image设置如下:
pbAvatar.Image = new Bitmap(filePath);
Run Code Online (Sandbox Code Playgroud)
如何解锁第一个文件?
Bri*_*ian 50
这是我打开图像而不锁定文件的方法...
public static Image FromFile(string path)
{
var bytes = File.ReadAllBytes(path);
var ms = new MemoryStream(bytes);
var img = Image.FromStream(ms);
return img;
}
Run Code Online (Sandbox Code Playgroud)
更新:我做了一些性能测试,看看哪种方法最快.我将它与@net_progs"从位图复制"答案(这似乎是最接近正确的,但确实有一些问题)进行了比较.我为每种方法加载了10000次图像并计算了每张图像的平均时间.结果如下:
Loading from bytes: ~0.26 ms per image.
Copying from bitmap: ~0.50 ms per image.
Run Code Online (Sandbox Code Playgroud)
结果似乎有意义,因为您必须使用位图方法的副本创建图像两次.
更新:如果您需要BitMap,您可以:
return (Bitmap)Image.FromStream(ms);
Run Code Online (Sandbox Code Playgroud)
net*_*rog 39
这是在网络上广泛讨论的常见锁定问题.
使用流的建议技巧将无法工作,实际上它最初工作,但稍后会导致问题.例如,它将加载图像,文件将保持解锁状态,但如果您尝试通过Save()方法保存加载的图像,它将抛出一个通用的GDI +异常.
接下来,每像素复制的方式似乎并不牢固,至少它是嘈杂的.
我发现的工作原理如下:http://www.eggheadcafe.com/microsoft/Csharp/35017279/imagefromfile--locks-file.aspx
这是应该加载图像的方式:
Image img;
using (var bmpTemp = new Bitmap("image_file_path"))
{
img = new Bitmap(bmpTemp);
}
Run Code Online (Sandbox Code Playgroud)
我一直在寻找这个问题的解决方案,这个方法到目前为止对我来说很好,所以我决定对它进行描述,因为我发现许多人在这里和网上都提出了错误的流方法.
Pon*_*dum 26
使用文件流将在文件读取和处理后解锁:
using (var fs = new System.IO.FileStream("c:\\path to file.bmp", System.IO.FileMode.Open))
{
var bmp = new Bitmap(fs);
pct.Image = (Bitmap) bmp.Clone();
}
Run Code Online (Sandbox Code Playgroud)
编辑:已更新以允许处置原始位图,并允许关闭FileStream.
这个答案并不安全 - 请参阅评论,并参见net_prog的答案中的讨论.要使用的编辑Clone
不会使它更安全 - 克隆克隆所有字段,包括文件流引用,在某些情况下会导致问题.
当位图对象仍在使用它时,您无法处置/关闭流.(如果你知道你正在使用什么类型的文件以及你将要执行什么操作,那么位图对象是否需要再次访问它只是确定性的 - 例如对于SOME .gif格式图像,流之前关闭构造函数返回.)
克隆创建位图的"精确副本"(每个文档; ILSpy显示它调用本机方法,所以现在跟踪太多了)可能,它也复制了Stream数据 - 否则它不会是精确的副本.
你最好的选择是创建一个像素完美的图像复制品 - 虽然YMMV(某些类型的图像可能有多个帧,或者你可能也需要复制调色板数据.)但对于大多数图像,这是有效的:
static Bitmap LoadImage(Stream stream)
{
Bitmap retval = null;
using (Bitmap b = new Bitmap(stream))
{
retval = new Bitmap(b.Width, b.Height, b.PixelFormat);
using (Graphics g = Graphics.FromImage(retval))
{
g.DrawImage(b, Point.Empty);
g.Flush();
}
}
return retval;
}
Run Code Online (Sandbox Code Playgroud)
然后你可以像这样调用它:
using (Stream s = ...)
{
Bitmap x = LoadImage(s);
}
Run Code Online (Sandbox Code Playgroud)
据我所知,这是 100% 安全的,因为生成的图像 100% 是在内存中创建的,没有任何链接资源,并且没有在内存中留下任何打开的流。它的作用类似于Bitmap
从不指定任何输入源的构造函数创建的任何其他答案,并且与此处的其他一些答案不同,它保留了原始像素格式,这意味着它可以用于索引格式。
基于这个答案,但有额外的修复并且没有外部库导入。
/// <summary>
/// Clones an image object to free it from any backing resources.
/// Code taken from http://stackoverflow.com/a/3661892/ with some extra fixes.
/// </summary>
/// <param name="sourceImage">The image to clone</param>
/// <returns>The cloned image</returns>
public static Bitmap CloneImage(Bitmap sourceImage)
{
Rectangle rect = new Rectangle(0, 0, sourceImage.Width, sourceImage.Height);
Bitmap targetImage = new Bitmap(rect.Width, rect.Height, sourceImage.PixelFormat);
targetImage.SetResolution(sourceImage.HorizontalResolution, sourceImage.VerticalResolution);
BitmapData sourceData = sourceImage.LockBits(rect, ImageLockMode.ReadOnly, sourceImage.PixelFormat);
BitmapData targetData = targetImage.LockBits(rect, ImageLockMode.WriteOnly, targetImage.PixelFormat);
Int32 actualDataWidth = ((Image.GetPixelFormatSize(sourceImage.PixelFormat) * rect.Width) + 7) / 8;
Int32 h = sourceImage.Height;
Int32 origStride = sourceData.Stride;
Boolean isFlipped = origStride < 0;
origStride = Math.Abs(origStride); // Fix for negative stride in BMP format.
Int32 targetStride = targetData.Stride;
Byte[] imageData = new Byte[actualDataWidth];
IntPtr sourcePos = sourceData.Scan0;
IntPtr destPos = targetData.Scan0;
// Copy line by line, skipping by stride but copying actual data width
for (Int32 y = 0; y < h; y++)
{
Marshal.Copy(sourcePos, imageData, 0, actualDataWidth);
Marshal.Copy(imageData, 0, destPos, actualDataWidth);
sourcePos = new IntPtr(sourcePos.ToInt64() + origStride);
destPos = new IntPtr(destPos.ToInt64() + targetStride);
}
targetImage.UnlockBits(targetData);
sourceImage.UnlockBits(sourceData);
// Fix for negative stride on BMP format.
if (isFlipped)
targetImage.RotateFlip(RotateFlipType.Rotate180FlipX);
// For indexed images, restore the palette. This is not linking to a referenced
// object in the original image; the getter of Palette creates a new object when called.
if ((sourceImage.PixelFormat & PixelFormat.Indexed) != 0)
targetImage.Palette = sourceImage.Palette;
// Restore DPI settings
targetImage.SetResolution(sourceImage.HorizontalResolution, sourceImage.VerticalResolution);
return targetImage;
}
Run Code Online (Sandbox Code Playgroud)
要调用,只需使用:
/// <summary>Loads an image without locking the underlying file.</summary>
/// <param name="path">Path of the image to load</param>
/// <returns>The image</returns>
public static Bitmap LoadImageSafe(String path)
{
using (Bitmap sourceImage = new Bitmap(path))
{
return CloneImage(sourceImage);
}
}
Run Code Online (Sandbox Code Playgroud)
或者,从字节:
/// <summary>Loads an image from bytes without leaving open a MemoryStream.</summary>
/// <param name="fileData">Byte array containing the image to load.</param>
/// <returns>The image</returns>
public static Bitmap LoadImageSafe(Byte[] fileData)
{
using (MemoryStream stream = new MemoryStream(fileData))
using (Bitmap sourceImage = new Bitmap(stream)) {
{
return CloneImage(sourceImage);
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
39890 次 |
最近记录: |