上传的文件被GDI读取后锁定
我有以下 ImageObject 类:
public class ImageObject
{
public static Image CropImage(Image img, Rectangle cropArea)
{
Bitmap bmpImage = new Bitmap(img);
Bitmap target = new Bitmap(cropArea.Width, cropArea.Height);
using(Graphics g = Graphics.FromImage(target))
{
g.DrawImage(bmpImage, new Rectangle(0, 0, target.Width, target.Height), cropArea, GraphicsUnit.Pixel);
g.Dispose();
}
return (Image)target;
}
public static Image ResizeImage(Image imgToResize, Size size)
{
int sourceWidth = imgToResize.Width;
int sourceHeight = imgToResize.Height;
float nPercent = 0;
float nPercentW = 0;
float nPercentH = 0;
nPercentW = ((float)size.Width / (float)sourceWidth);
nPercentH = ((float)size.Height / (float)sourceHeight);
if (nPercentH < nPercentW)
nPercent = nPercentH;
else
nPercent = nPercentW;
int destWidth = (int)(sourceWidth * nPercent);
int destHeight = (int)(sourceHeight * nPercent);
Bitmap b = new Bitmap(destWidth, destHeight);
//Graphics g = Graphics.FromImage((Image)b);
using(Graphics g = Graphics.FromImage((Image)b))
{
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImage(imgToResize, 0, 0, destWidth, destHeight);
g.Dispose();
}
return (Image)b;
}
public static void SaveJpeg(string path, System.Drawing.Image source, long quality)
{
EncoderParameter qualityParam = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, quality);
ImageCodecInfo jpegCodec = GetEncoderInfo("image/jpeg");
if (jpegCodec == null)
return;
EncoderParameters encoderParams = new EncoderParameters(1);
encoderParams.Param[0] = qualityParam;
source.Save(path, jpegCodec, encoderParams);
}
private static ImageCodecInfo GetEncoderInfo(string mimeType)
{
// Get image codecs for all image formats
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
// Find the correct image codec
for (int i = 0; i < codecs.Length; i++)
if (codecs[i].MimeType == mimeType)
return codecs[i];
return null;
}
}
我从另一个类中的函数引用此代码:
public static void CreateAvatar(string filepath, int x, int y, int w, int h)
{
var big = filepath + "100x100.jpg";
var medium = filepath + "40x40.jpg";
var small = filepath + "25x25.jpg";
var full_path = filepath + "avatar.jpg";
var temp_path = filepath + "avatar_t.jpg";
if (File.Exists(big))
{
File.Delete(big);
}
if (File.Exists(medium))
{
File.Delete(medium);
}
if (File.Exists(small))
{
File.Delete(small);
}
if (File.Exists(temp_path))
{
File.Delete(temp_path);
}
System.Drawing.Image img = System.Drawing.Image.FromFile(full_path);
System.Drawing.Rectangle rect = new Rectangle(x, y, w, h);
System.Drawing.Size hundred = new Size(100, 100);
System.Drawing.Size forty = new Size(40, 40);
System.Drawing.Size twentyfive = new Size(25, 25);
//we crop, then we resize...
var cropped = ImageObject.CropImage(img, rect);
ImageObject.SaveJpeg(temp_path, cropped, 100L);
//problems usually from here. can't save big, because it can't read temp_path - it's locked...
var resize_big = ImageObject.ResizeImage(System.Drawing.Image.FromFile(temp_path), hundred);
ImageObject.SaveJpeg(big, resize_big, 100L);
var resize_forty = ImageObject.ResizeImage(System.Drawing.Image.FromFile(temp_path), forty);
ImageObject.SaveJpeg(medium, resize_forty, 100L);
var resize_twentyfive = ImageObject.ResizeImage(System.Drawing.Image.FromFile(temp_path), twentyfive);
ImageObject.SaveJpeg(small, resize_twentyfive, 100L);
}
此方法由 Web 服务调用。第一次执行此代码时(IIS 重新启动后),一切正常,但如果再次使用,则会挂起。我知道这与我创建的两个图像有关:avatar.jpg
和 avatar_t.jpg
。我知道这一点是因为我无法删除或重命名资源管理器中的图像:
我已确保我有 <按照许多人的建议,对 Graphics
对象进行了 code>Dispose 处理,但我不明白为什么锁不会释放?任何人都可以看到问题吗?
理想情况下,我想在底部执行此操作:
var resize_twentyfive = ImageObject.ResizeImage(System.Drawing.Image.FromFile(temp_path), twentyfive);
ImageObject.SaveJpeg(small, resize_twentyfive, 100L);
//clean up, delete avatar.jpg and avatar_t.jpg
File.Delete(temp_path);
File.Delete(full_path);
并删除我用来读取的图像 - 它们不再需要。我不介意它们留在那里,只要我可以从上传者那里随意覆盖它们......
I have the following ImageObject class:
public class ImageObject
{
public static Image CropImage(Image img, Rectangle cropArea)
{
Bitmap bmpImage = new Bitmap(img);
Bitmap target = new Bitmap(cropArea.Width, cropArea.Height);
using(Graphics g = Graphics.FromImage(target))
{
g.DrawImage(bmpImage, new Rectangle(0, 0, target.Width, target.Height), cropArea, GraphicsUnit.Pixel);
g.Dispose();
}
return (Image)target;
}
public static Image ResizeImage(Image imgToResize, Size size)
{
int sourceWidth = imgToResize.Width;
int sourceHeight = imgToResize.Height;
float nPercent = 0;
float nPercentW = 0;
float nPercentH = 0;
nPercentW = ((float)size.Width / (float)sourceWidth);
nPercentH = ((float)size.Height / (float)sourceHeight);
if (nPercentH < nPercentW)
nPercent = nPercentH;
else
nPercent = nPercentW;
int destWidth = (int)(sourceWidth * nPercent);
int destHeight = (int)(sourceHeight * nPercent);
Bitmap b = new Bitmap(destWidth, destHeight);
//Graphics g = Graphics.FromImage((Image)b);
using(Graphics g = Graphics.FromImage((Image)b))
{
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImage(imgToResize, 0, 0, destWidth, destHeight);
g.Dispose();
}
return (Image)b;
}
public static void SaveJpeg(string path, System.Drawing.Image source, long quality)
{
EncoderParameter qualityParam = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, quality);
ImageCodecInfo jpegCodec = GetEncoderInfo("image/jpeg");
if (jpegCodec == null)
return;
EncoderParameters encoderParams = new EncoderParameters(1);
encoderParams.Param[0] = qualityParam;
source.Save(path, jpegCodec, encoderParams);
}
private static ImageCodecInfo GetEncoderInfo(string mimeType)
{
// Get image codecs for all image formats
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
// Find the correct image codec
for (int i = 0; i < codecs.Length; i++)
if (codecs[i].MimeType == mimeType)
return codecs[i];
return null;
}
}
And I reference this code from a function in another class:
public static void CreateAvatar(string filepath, int x, int y, int w, int h)
{
var big = filepath + "100x100.jpg";
var medium = filepath + "40x40.jpg";
var small = filepath + "25x25.jpg";
var full_path = filepath + "avatar.jpg";
var temp_path = filepath + "avatar_t.jpg";
if (File.Exists(big))
{
File.Delete(big);
}
if (File.Exists(medium))
{
File.Delete(medium);
}
if (File.Exists(small))
{
File.Delete(small);
}
if (File.Exists(temp_path))
{
File.Delete(temp_path);
}
System.Drawing.Image img = System.Drawing.Image.FromFile(full_path);
System.Drawing.Rectangle rect = new Rectangle(x, y, w, h);
System.Drawing.Size hundred = new Size(100, 100);
System.Drawing.Size forty = new Size(40, 40);
System.Drawing.Size twentyfive = new Size(25, 25);
//we crop, then we resize...
var cropped = ImageObject.CropImage(img, rect);
ImageObject.SaveJpeg(temp_path, cropped, 100L);
//problems usually from here. can't save big, because it can't read temp_path - it's locked...
var resize_big = ImageObject.ResizeImage(System.Drawing.Image.FromFile(temp_path), hundred);
ImageObject.SaveJpeg(big, resize_big, 100L);
var resize_forty = ImageObject.ResizeImage(System.Drawing.Image.FromFile(temp_path), forty);
ImageObject.SaveJpeg(medium, resize_forty, 100L);
var resize_twentyfive = ImageObject.ResizeImage(System.Drawing.Image.FromFile(temp_path), twentyfive);
ImageObject.SaveJpeg(small, resize_twentyfive, 100L);
}
This method is called by a web service. On the first execution of this code (after an IIS restart), all is well, but if used again it hangs. I know it has to do with the two images I have created: avatar.jpg
and avatar_t.jpg
. I know this because I cannot delete or rename the images in Explorer:
I have ensured I have Dispose
'd the Graphics
objects as suggested by many, but I can't figure out why the locks won't release? Can anyone see the problem?
Ideally, I'd like to do this at the bottom:
var resize_twentyfive = ImageObject.ResizeImage(System.Drawing.Image.FromFile(temp_path), twentyfive);
ImageObject.SaveJpeg(small, resize_twentyfive, 100L);
//clean up, delete avatar.jpg and avatar_t.jpg
File.Delete(temp_path);
File.Delete(full_path);
And delete the images I used to read from - they are no longer needed. I don't mind them staying there, so long as I can then overwrite them at will from the uploader...
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
System.Drawing.Image.FromFile()
在您对图像调用 Dispose 之前,不会关闭文件。位图和图像构造函数依赖项:
Image.FromFile()
是一个非常糟糕的 API 方法(从某种意义上说,它会让开发人员陷入失败!)。问题的原因是:再次引用支持文章:
System.Drawing.Image.FromFile()
does not close the file until you call Dispose on the image.Bitmap and Image constructor dependencies:
Image.FromFile()
is a very poor API method (in the sense that it sets the developer up for failure!). The problem is caused by:Again, quoting from the support article: