C#裁剪和调整大型图像大小

7

我有一些非常大的建筑图纸,有时候是22466x3999,位深度为24,甚至更大。

我需要能够将这些图像调整为较小的版本,并能够剪切图像的部分以生成较小的图像。

我一直在使用以下代码来调整图像的大小,我在这里找到了它:

       public static void ResizeImage(string OriginalFile, string NewFile, int NewWidth, int MaxHeight, bool OnlyResizeIfWider)
        {
            System.Drawing.Image FullsizeImage = System.Drawing.Image.FromFile(OriginalFile);
            if (OnlyResizeIfWider)
            {
                if (FullsizeImage.Width <= NewWidth)
                {
                    NewWidth = FullsizeImage.Width;
                }
            }
            int NewHeight = FullsizeImage.Height * NewWidth / FullsizeImage.Width;
            if (NewHeight > MaxHeight)
            {
                NewWidth = FullsizeImage.Width * MaxHeight / FullsizeImage.Height;
                NewHeight = MaxHeight;
            }
            System.Drawing.Image NewImage = FullsizeImage.GetThumbnailImage(NewWidth, NewHeight, null, IntPtr.Zero);
            FullsizeImage.Dispose();
            NewImage.Save(NewFile);
        }

这段代码用于裁剪图片:

public static MemoryStream CropToStream(string path, int x, int y, int width, int height)
        {
            if (string.IsNullOrWhiteSpace(path)) return null;
            Rectangle fromRectangle = new Rectangle(x, y, width, height);
            using (Image image = Image.FromFile(path, true))
            {
                Bitmap target = new Bitmap(fromRectangle.Width, fromRectangle.Height);
                using (Graphics g = Graphics.FromImage(target))
                {
                    Rectangle croppedImageDimentions = new Rectangle(0, 0, target.Width, target.Height);
                    g.DrawImage(image, croppedImageDimentions, fromRectangle, GraphicsUnit.Pixel);
                }
                MemoryStream stream = new MemoryStream();
                target.Save(stream, image.RawFormat);
                stream.Position = 0;
                return stream;
            }
        }

我的问题是当我尝试调整图像大小时,会出现Sytem.OutOfMemoryException错误,这是因为我无法将完整的图像加载到FullsizeImage中。

所以我想知道,如何在不将整个图像加载到内存中的情况下调整图像大小?


这不是一个编程解决方案,但你可以尝试增加你的机器的虚拟内存大小来看看。 - Kurubaran
针对这样的图像大小,您应该使用LockBits进行处理。 - Vajura
@Kurubaran 我尝试增加内存大小,但没有起作用,我认为这不是 Web 项目的正确解决方案。 - Martin M
2个回答

5
有可能OutOfMemoryException不是由于图像大小,而是因为您没有正确释放所有可处理的类:

  • Bitmap target
  • MemoryStream stream
  • System.Drawing.Image NewImage

应该按照规定对它们进行using()语句的添加。

如果您只遇到一个图像出现此错误,则应考虑将项目切换到x64。22466x3999的图片在内存中占用225Mb,我认为对于x86来说这不应该成为问题。(所以首先尝试释放对象)。

最后但并非最不重要的是,Magick.Net非常高效地调整/裁剪大型图片。


谢谢,我会在Fullsizeimage和其他地方添加using()。我确实尝试过Magick.Net,但无法使其正常工作,如果这不起作用,我会再试一次。 - Martin M
Image Magick.Net应该是最好的选择,因为添加using仍然会返回“OutOfMemoryException”。如果Image Magick.Net无法工作,我将创建一个单独的服务来处理所有图像调整大小和裁剪。 - Martin M
1
即使在大型的64位系统上,也无法创建任意大小的位图。如果他需要处理真正大的位图,恐怕使用第三方库是最好的选择。 - TaW
我觉得我需要对这个问题进行跟进,在添加了一些using之后,它最终起作用了。我想你是对的,我在多次使用该方法后,某些时候会出现异常。所以谢谢你!另一个问题可能是它是一个Web应用程序,因此内存可能受到IIS内存限制的限制。 - Martin M

1
你也可以强制 .Net 直接从磁盘读取图像并停止内存缓存。
使用: sourceBitmap = (Bitmap)Image.FromStream(sourceFileStream, false, false); 而不是 ...System.Drawing.Image.FromFile(OriginalFile); 参见 https://dev59.com/K0jSa4cB1Zd3GeqPCRSl#47424918

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接