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

Posted

技术标签:

【中文标题】C# 裁剪和调整大图像大小【英文标题】:C# Crop & resize large images 【发布时间】:2015-03-13 08:50:39 【问题描述】:

我得到了一些非常大的建筑图纸,有时是 22466x3999,位深为 24,甚至更大。 我需要能够将这些调整为更小的版本,并且能够将图像的部分剪切成更小的图像。

我一直在使用以下代码来调整图像大小,我发现here:

       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。

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

【问题讨论】:

这不是编程解决方案,但您可以尝试增加机器的虚拟内存大小并查看。 你应该使用 LockBits 来处理这样的图像尺寸 @Kurubaran 我尝试增加内存大小,但没有成功,我认为这不是 web 项目的正确解决方案。 【参考方案1】:

OutOfMemoryException 有可能不是因为图像的大小,而是因为您没有正确处理所有一次性用品类:

Bitmap target MemoryStream stream System.Drawing.Image NewImage

没有按应有的方式处置。您应该在它们周围添加一个using() 声明。

如果您真的只使用一张图像遇到此错误,那么您应该考虑将您的项目切换到 x64。一张 22466x3999 的图片意味着 225Mb 的内存,我认为这对于 x86 来说应该不是问题。 (所以请先尝试处理您的对象)。

最后但同样重要的是,Magick.Net 在调整/裁剪大图片方面非常有效。

【讨论】:

谢谢,我会把using()加到Fullsizeimage和其他地方。我确实尝试过 Magick.Net,但我无法让它工作,但如果这没有帮助,我会试一试。 Image Magick.Net 必须是要走的路,因为添加 using 仍然返回 OutOfMemoryException。如果 Image Magick.Net 不起作用,我将创建一个单独的服务来处理所有图像大小调整和裁剪.. 即使在大型 64 位系统上,您也无法创建任意大小的位图。如果他需要处理非常大的位图,恐怕使用 3rd 方库是最好的选择.. 我觉得我需要对这个问题进行跟进,在添加了几个使用之后,它最终工作了。我认为您是对的,我多次使用该方法,并且在某些时候我会遇到异常。所以谢谢!另一个问题可能是它是一个 Web 应用程序,因此内存可能受到 IIS 内存上限的限制。【参考方案2】:

您还可以强制 .Net 直接从磁盘读取图像并停止内存缓存。

使用

sourceBitmap = (Bitmap)Image.FromStream(sourceFileStream, false, false);

代替

...System.Drawing.Image.FromFile(OriginalFile);

见https://***.com/a/47424918/887092

【讨论】:

以上是关于C# 裁剪和调整大图像大小的主要内容,如果未能解决你的问题,请参考以下文章

ImageMagick:转换、裁剪、调整大图像

使用 Imagemagick 将大图像裁剪为特定的纵横比,然后调整它们的大小

如何使用 Open CV 3 python 3 用鼠标从大图像中裁剪 ROI

带有大图像的 jQuery 裁剪工具

C#:同时调整图像大小和裁剪

C# 图像裁剪器 + 大小调整器