【问题标题】:Resize image gdi+ graphics .net调整图像gdi +图形.net
【发布时间】:2010-12-07 15:19:13
【问题描述】:

我有这种方法可以缩小我正在开发的网站的图像:

static byte[] createSmallerImage(
   BlogPhoto blogPhoto, 
   int newMaxWidth, 
   int newMaxHeight)
{
  Image img;
  using (MemoryStream originalImage = 
           new MemoryStream(blogPhoto.BlogPhotoImage))
  {
    img = Image.FromStream(originalImage);
  }

  int newWidth;
  int newHeight;
  byte[] arr;

  if (img.Width > img.Height)
  {
    if (img.Width <= newMaxWidth)
    {

      using (MemoryStream thumbStr = new MemoryStream())
      {
        img.Save(thumbStr, ImageFormat.Jpeg);
        img.Dispose();
        arr = thumbStr.ToArray();
      }
      return arr;
    }

    newWidth = newMaxWidth;
    newHeight = 
       (int)(((float)newWidth / (float)img.Width) * (float)img.Height);
  }
  else
  {
    if (img.Height <= newMaxHeight)
    {

      using (MemoryStream thumbStr = new MemoryStream())
      {
        img.Save(thumbStr, ImageFormat.Jpeg);
        img.Dispose();
        arr = thumbStr.ToArray();
      }
      return arr;
    }

    newHeight = newMaxHeight;
    newWidth = 
      (int)(((float)newHeight / (float)img.Height) * (float)img.Width);
  }

  Image thumb = new Bitmap(newWidth, newHeight);

  Graphics g = Graphics.FromImage(thumb);
  g.InterpolationMode = InterpolationMode.HighQualityBicubic;
  g.SmoothingMode = SmoothingMode.HighQuality;
  g.PixelOffsetMode = PixelOffsetMode.HighQuality;
  g.CompositingQuality = CompositingQuality.HighQuality;

  g.DrawImage(img, 0f, 0f, (float)newWidth, (float)newHeight);


  using (MemoryStream thumbStr = new MemoryStream())
  {
    thumb.Save(thumbStr, ImageFormat.Jpeg);
    arr = thumbStr.ToArray();
  }

  g.Dispose();
  img.Dispose();

  return arr;
}

大多数时候它工作得很好,但有时它会给我这个异常:GDI+ 中发生一般错误。错误代码 -2147467259。来源:“System.Drawing”。这会在 Image.Save(...

【问题讨论】:

  • 您是否尝试保存到您加载的同一个文件?
  • blogPhoto.BlogPhotoImage 是从 linq-to-sql 检索到的 byte[]

标签: c# .net gdi+


【解决方案1】:

我个人使用这段代码,没有流(不过我不关心性能)来调整图片大小:

public Image resizeImage(int newWidth, int newHeight, string stPhotoPath)
 {
     Image imgPhoto = Image.FromFile(stPhotoPath); 

     int sourceWidth = imgPhoto.Width;
     int sourceHeight = imgPhoto.Height;

     //Consider vertical pics
    if (sourceWidth < sourceHeight)
    {
        int buff = newWidth;

        newWidth = newHeight;
        newHeight = buff;
    }

    int sourceX = 0, sourceY = 0, destX = 0, destY = 0;
    float nPercent = 0, nPercentW = 0, nPercentH = 0;

    nPercentW = ((float)newWidth / (float)sourceWidth);
    nPercentH = ((float)newHeight / (float)sourceHeight);
    if (nPercentH < nPercentW)
    {
        nPercent = nPercentH;
        destX = System.Convert.ToInt16((newWidth -
              (sourceWidth * nPercent)) / 2);
    }
    else
    {
        nPercent = nPercentW;
        destY = System.Convert.ToInt16((newHeight -
              (sourceHeight * nPercent)) / 2);
    }

    int destWidth = (int)(sourceWidth * nPercent);
    int destHeight = (int)(sourceHeight * nPercent);


    Bitmap bmPhoto = new Bitmap(newWidth, newHeight,
              PixelFormat.Format24bppRgb);

    bmPhoto.SetResolution(imgPhoto.HorizontalResolution,
             imgPhoto.VerticalResolution);

    Graphics grPhoto = Graphics.FromImage(bmPhoto);
    grPhoto.Clear(Color.Black);
    grPhoto.InterpolationMode =
        InterpolationMode.HighQualityBicubic;

    grPhoto.DrawImage(imgPhoto,
        new Rectangle(destX, destY, destWidth, destHeight),
        new Rectangle(sourceX, sourceY, sourceWidth, sourceHeight),
        GraphicsUnit.Pixel);

    grPhoto.Dispose();
    return bmPhoto;
}

希望这会有所帮助。

【讨论】:

    【解决方案2】:

    查看 Image.FromStream() 的文档

    http://msdn.microsoft.com/en-us/library/93z9ee4x.aspx

    您需要在图像的生命周期内保持流打开。让第一个 MemoryStream 打开更长的时间,它应该可以工作。

    【讨论】:

    • 底层 GDI+ 图像类不需要保持流打开,这非常很奇怪。 (msdn.microsoft.com/en-us/library/ms535371.aspx) 但是通过反射器我最终明白了原因:他们必须将 .NET 流包装到适合 GDI+ 的 IStream 中。接口是引用计数的,而 .NET Stream 对象则不是。由于它们仅将流对象包装在新接口中,而不是复制实际数据,因此您必须保留源对象。
    【解决方案3】:

    要查看的一件事是 blogPhoto 和底层数据正在消失。它从哪里加载?它是从流中加载的吗?该流是否在 createSmallerImage 之前关闭?从流已关闭的流中加载的图像在 95% 的时间内都可以正常工作,并且仅偶尔会引发通用 GDI+ 错误。

    【讨论】:

    • BlogPhotoImage 是从 linq-to-sql 加载的延迟加载字节 []。
    • 您是直接加载还是从 MemoryStream 加载?在调用 createSmallerImage 之前是否有可能超出范围?
    【解决方案4】:

    我不知道会发生什么,但也许少了MemoryStreams 问题就消失了:

    using (Image original = Image.FromStream(new MemoryStream(blogPhoto)))
    {
        using (MemoryStream thumbData = new MemoryStream())
        {
            int newWidth;
            int newHeight;
            if ((original.Width <= newMaxWidth) || 
                (original.Height <= newMaxHeight))
            {
                original.Save(thumbData, ImageFormat.Jpeg);
                return thumbData.ToArray();
            }
    
            if (original.Width > original.Height)
            {
                newWidth = newMaxWidth;
                newHeight = (int)(((float)newWidth / 
                    (float)original.Width) * (float)original.Height);
            }
            else
            {
                newHeight = newMaxHeight;
                newWidth = (int)(((float)newHeight / 
                    (float)original.Height) * (float)original.Width);
            }
    
            //original.GetThumbnailImage(newWidth, newHeight, null, IntPtr.Zero)
            //    .Save(thumbData, ImageFormat.Jpeg);
            //return thumbData.ToArray();
    
            using (Image thumb = new Bitmap(newWidth, newHeight))
            {
                Graphics g = Graphics.FromImage(thumb);
                g.InterpolationMode = InterpolationMode.HighQualityBicubic;
                g.SmoothingMode = SmoothingMode.HighQuality;
                g.PixelOffsetMode = PixelOffsetMode.HighQuality;
                g.CompositingQuality = CompositingQuality.HighQuality;
                g.DrawImage(original, 0f, 0f, (float)newWidth, (float)newHeight);
                thumb.Save(thumbData, ImageFormat.Jpeg);
            }
        }
    }
    

    【讨论】:

    • 我很困惑这将如何工作,因为您正在调用它:img.Save(imageSource, ImageFormat.Jpeg);和 thumb.Save(imageSource, ImageFormat.Jpeg);然后返回 imageSource.ToArray();这不会导致内存流中有两个图像吗?
    • 对不起,我的错误;您可以依靠 GetThumbnailImage 来完成工作吗?我刚刚更新了我的答案以使用这种方法。
    • 我想我可以(如果此错误仍然存​​在,我可以尝试)但规范说:当请求的缩略图图像的大小约为 120 x 120 像素时,GetThumbnailImage 方法效果很好。如果您从具有嵌入式缩略图的图像中请求较大的缩略图图像(例如,300 x 300),则缩略图图像的质量可能会明显下降。通过调用 DrawImage 方法来缩放主图像(而不是缩放嵌入的缩略图)可能会更好。这可能不适合我创建更大的缩略图。
    猜你喜欢
    • 1970-01-01
    • 2013-11-28
    • 1970-01-01
    • 2011-02-21
    • 2014-05-13
    • 2010-12-07
    • 2016-04-26
    • 1970-01-01
    • 2012-06-20
    相关资源
    最近更新 更多