GDI读取后上载文件锁

时间:2011-08-12 10:36:55

标签: c# io 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.jpgavatar_t.jpg。我知道这是因为我无法在资源管理器中删除或重命名图像:

locked file when trying to rename

我已经确保我有许多Dispose Graphicsvar 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); 个对象,但我无法弄清楚为什么锁不会释放?有谁能看到这个问题?

理想情况下,我想在底部执行此操作:

{{1}}

删除我以前读取的图像 - 不再需要它们。我不介意他们留在那里,只要我可以随意覆盖上传者......

1 个答案:

答案 0 :(得分:6)

在您在图像上调用Dispose之前,

System.Drawing.Image.FromFile()不会关闭文件。

Bitmap and Image constructor dependencies

  

从a构造Bitmap对象或Image对象时   文件,文件在对象的生命周期内保持锁定状态。作为一个   结果,您无法更改图像并将其保存回同一文件   它起源于哪里。

     

另外,如果流在生命周期中被破坏了   位图对象,您无法成功访问基于的图像   在一条小溪上。例如,Graphics.DrawImage()函数可能不会   在流被破坏后成功

Image.FromFile()是一种非常差的API方法(从某种意义上说它会让开发人员失败!)。问题是由以下原因引起的:

  

GDI +,因此System.Drawing命名空间可能会推迟   解码原始图像位直到图像需要位。   另外,即使在图像被解码之后,GDI +也可以   确定丢弃大内存的效率更高   位图并稍后重新解码。因此,GDI +必须能够访问   位图或图像生命周期中图像的源位   宾语。

     

为了保持对源位的访问,GDI +锁定任何源文件,和   强制应用程序维护任何源流的生命周期   Bitmap或Image对象的生命周期。

再次引用支持文章:

  

要解决此问题,请使用以下方法之一创建新的位图图像   以下方法(如本节后面所述):

     
      
  • 创建非索引图像。
  •   
  • 创建索引图像。
  •   
     

在这两种情况下,都要调用原始的Bitmap.Dispose()方法   位图删除文件上的锁定或删除该要求   流或记忆保持活力。

相关问题