Pio*_*trK 9 .net c# system.drawing
更新
我使用下面的解决方案(从流加载图像),但得到新的问题.img对象绝对正确Image类实例,所有字段都填充了正确的值.但是打电话
img.Save("path/to/new/image.bmp");
Run Code Online (Sandbox Code Playgroud)
在它上面导致GDI +的新异常(System.Runtime.InteropServices.ExternalException,在GDI +接口中) - 我收到错误消息但是很好,我不知道如何翻译它.
原始问题
我有C#.NET Framework 2.0的问题
基本上我试图实现:
Image img = Image.FromFile("Path/To/Image.bmp");
File.Delete("Path/To/Image.bmp"); // Exception, the file is in use!
Run Code Online (Sandbox Code Playgroud)
删除原始文件时,将图像副本保留在内存中非常重要.我虽然有点奇怪,.NET仍然锁定硬盘上的文件,尽管它不再需要任何操作(整个图像现在在内存中,不是吗?)
所以我试过这个解决方案:
Image img = new Image(Image.FromFile("Path/To/Image.bmp")); // Make a copy
// this should immiedietaly destroy original loaded image
File.Delete("Path/To/Image.bmp"); // Still exception: the file is in use!
Run Code Online (Sandbox Code Playgroud)
我可以:
Image img = null;
using(Image imgTmp = Image.FromFile("Path/To/Image.bmp"))
{
img = new Bitmap(imgTmp.Width, imgTmp.Height, imgTmp.PixelFormat);
Graphics gdi = Graphics.FromIage(img);
gdi.DrawImageUnscaled(imgTmp, 0, 0);
gdi.Dispose();
imgTmp.Dispose(); // just to make sure
}
File.Delete("Path/To/Image.bmp"); // Works fine
// So I have img!
Run Code Online (Sandbox Code Playgroud)
但在我看来,这几乎就像使用nuke来杀死bug ......并引发了另一个问题:GDI很难支持将基于调色板的图像相互映射(并且调色板在我的收藏中占多数).
难道我做错了什么?有没有更好的方法让内存中的图像和原始文件从硬盘中删除?
Jor*_*dão 17
这应该做的伎俩:
Image img = null;
using (var stream = File.OpenRead(path)) {
img = Image.FromStream(stream);
}
File.Delete(path);
Run Code Online (Sandbox Code Playgroud)
更新:不要使用上面的代码!
我找到了相关的知识库文章:http://support.microsoft.com/?id = 814675
解决方案是真正复制文章中概述的位图.我编写了文章提到的两种方式(第一种是你正在做的那种,第二种是你答案中的那种,但没有使用unsafe):
public static Image CreateNonIndexedImage(string path) {
using (var sourceImage = Image.FromFile(path)) {
var targetImage = new Bitmap(sourceImage.Width, sourceImage.Height,
PixelFormat.Format32bppArgb);
using (var canvas = Graphics.FromImage(targetImage)) {
canvas.DrawImageUnscaled(sourceImage, 0, 0);
}
return targetImage;
}
}
[DllImport("Kernel32.dll", EntryPoint = "CopyMemory")]
private extern static void CopyMemory(IntPtr dest, IntPtr src, uint length);
public static Image CreateIndexedImage(string path) {
using (var sourceImage = (Bitmap)Image.FromFile(path)) {
var targetImage = new Bitmap(sourceImage.Width, sourceImage.Height,
sourceImage.PixelFormat);
var sourceData = sourceImage.LockBits(
new Rectangle(0, 0, sourceImage.Width, sourceImage.Height),
ImageLockMode.ReadOnly, sourceImage.PixelFormat);
var targetData = targetImage.LockBits(
new Rectangle(0, 0, sourceImage.Width, sourceImage.Height),
ImageLockMode.WriteOnly, targetImage.PixelFormat);
CopyMemory(targetData.Scan0, sourceData.Scan0,
(uint)sourceData.Stride * (uint)sourceData.Height);
sourceImage.UnlockBits(sourceData);
targetImage.UnlockBits(targetData);
targetImage.Palette = sourceImage.Palette;
return targetImage;
}
}
Run Code Online (Sandbox Code Playgroud)
Kei*_*thS 10
你的问题是新的Image仍然知道它来自哪里,从旧的Image的复制构造函数中获得了文件句柄,因此运行时仍然知道它有一个打开的文件句柄.
您可以使用Stream来解决此问题:
Image image;
FileStream myStream = new FileStream(path);
try
{
image = Image.FromStream(myStream);
}
finally
{
myStream.Close();
myStream.Dispose();
}
//test that you have a valid Image and then go to work.
Run Code Online (Sandbox Code Playgroud)
这是一个带有using子句的清洁版:
Image image;
using(FileStream myStream = new FileStream(path))
{
image = Image.FromStream(myStream);
}
//a using clause calls Dispose() at the end of the block,
//which will call Close() as well
Run Code Online (Sandbox Code Playgroud)
买者自负; 我没有对此进行测试,也不能保证它能解决问题,但这似乎是合理的.直接使用Stream可以控制文件句柄,而不是图像实现,因此您可以确保程序在您需要时释放资源.
| 归档时间: |
|
| 查看次数: |
19508 次 |
| 最近记录: |