5

我需要縮小高度或寬度大於預定義像素值的圖像。C#中的圖像調整大小 - 確定調整大小尺寸(高度和寬度)的算法

我寫了一些代碼,看看原始圖像,檢查寬度,高度或高度和寬度是否大於最大寬度/最大高度設置。

我現在需要根據後者的最大值找出調整大小的尺寸。

例如:如果圖像是900h x 300w和最大高度爲700h我需要的高度700和寬度調整爲???? < - 這就是我需要計算..

創建和保存圖像文件很簡單,和這個職位的範圍:

// First I get the max height and width allowed: 

int resizeMaxHeight = int.Parse(Utility.GetConfigValue("ResizeMaxHeight")); // in config: 700px 
int resizeMaxWidth = int.Parse(Utility.GetConfigValue("ResizeMaxWidth")); // in config: 500px 

// Save original: 
try 
{ 
    filebase.SaveAs(savedFileName); 
} 
catch (System.IO.DirectoryNotFoundException ex) 
{ 
    Logger.Instance.LogException(ex, 0, "FileTransfer"); 
} 

// Determin original dimensions: 
Image image = System.Drawing.Image.FromFile(Server.MapPath(savedFileName)); 

int resizeHeight, resizeWidth; 
bool doResize = true; 

// both height and width are greater than the allowed height and width: 
if (image.Width > resizeMaxWidth && image.Height > resizeMaxHeight) 
{ 
    if (image.Height > image.Width) 
     resizeHeight = resizeMaxHeight; 
    else 
     resizeWidth = resizeMaxWidth; 
} 
else if (image.Width > resizeMaxWidth) 
{ 
    // width is too great, but height is ok 
    resizeWidth = resizeMaxWidth; 
} 
else if (image.Height > resizeMaxHeight) 
{ 
    // height is too great, but width is ok 
    resizeHeight = resizeMaxHeight; 
} 
else 
{ 
    // image is ok size, don't resize: 
    doResize = false; 
} 

創建縮略圖: 這就是我現在的工作...不完整:

if (doResize) 
{ 
    ImageUtilities.ResizeImage(image, resizeWidth, resizeHeight); 
} 

回答

7

以下是進行此計算的兩種方法。根據您對問題的看法,可能會比其他人更直觀。它們在數學上相當於小數點後幾位。

兩者對於Math.Round都是安全的,但只有ConstrainVerbose產生的結果總是小於maxWidth/maxHeight。

SizeF ConstrainConcise(int imageWidth, int imageHeight, int maxWidth, int maxHeight){ 
    // Downscale by the smallest ratio (never upscale) 
    var scale = Math.Min(1, Math.Min(maxWidth/(float)imageWidth, maxHeight/(float) imageHeight)); 
    return new SizeF(scale * imageWidth, scale * imageHeight); 
} 

SizeF ConstrainVerbose(int imageWidth, int imageHeight, int maxWidth, int maxHeight){ 
    // Coalculate the aspect ratios of the image and bounding box 
    var maxAspect = (float) maxWidth/(float) maxHeight; 
    var aspect = (float) imageWidth/(float) imageHeight; 
    // Bounding box aspect is narrower 
    if (maxAspect <= aspect && imageWidth > maxWidth) 
    { 
     // Use the width bound and calculate the height 
     return new SizeF(maxWidth, Math.Min(maxHeight, maxWidth/aspect)); 
    } 
    else if (maxAspect > aspect && imageHeight > maxHeight) 
    { 
     // Use the height bound and calculate the width 
     return new SizeF(Math.Min(maxWidth, maxHeight * aspect), maxHeight); 
    }else{ 
     return new SizeF(imageWidth, imageHeight); 
    } 
} 

Brute force unit-test here

+0

是是的是!計算長寬比。這是我正在尋找的術語。太棒了,非常感謝。 – nocarrier 2011-03-07 17:23:07

+2

不客氣。我建議你也讀這篇文章 - 有很多陷阱在.NET圖像調整大小,你應該避開: http://nathanaeljones.com/163/20-image-resizing-pitfalls/ – 2011-03-07 20:15:25

+0

這個答案實際上失敗,如果圖像比它寬廣! – 2017-12-05 09:00:05

2

我爲位圖類似的東西,但思路是一樣的:

1. get image height and width 
2. get current screen resolution 
3. calculate aspect ratio (ASR) from image size 

Handle following cases: 

4. if ASR >=1 and image width > image height 
    if image width > screen width {} 
     if image height > screen height {} 
     else if image width > screen width {} 
    else {} 
    else 
    if image height > screen height {} 
    else if image width > screen width {} 
    else {} 

// SCREEN_SIZE是可配置的; Defs.SCREEN_SIZE = 100; //和boolPixelAR爲true;

嘗試下面的代碼:

  // PERCENTAGE OF IMAGE -> TODO: Configurable? IMAZE ZOOM/SCREEN PERCENTAGE 
      Double HScale = __bmp.Width;// *Defs.SCREEN_SIZE/100; 
      Double VScale = __bmp.Height;// *Defs.SCREEN_SIZE/100; 
      Double __aspectRatio; 
      Double __screenRatio = _currentScreenSize.Width/_currentScreenSize.Height; 

      // PERCENTAGE OF SCREEN 
      if (!_boolPixelAR) { 
       HScale = _currentScreenSize.Width * Defs.SCREEN_SIZE/100; 
       VScale = _currentScreenSize.Height * Defs.SCREEN_SIZE/100; 
      } 
      else { 
       __aspectRatio = HScale/VScale; 
       if(__aspectRatio >= 1) 
        if (HScale >= _currentScreenSize.Width) { // Long Edge is WIDTH. For 100%, HScale = WIDTH 
         VScale = ((VScale * _currentScreenSize.Width)/HScale) * Defs.SCREEN_SIZE/100; 
         HScale = _currentScreenSize.Width * Defs.SCREEN_SIZE/100; 

         if (VScale > _currentScreenSize.Height) {     // Long Edge is HEIGHT. For 100%, VScale = HEIGHT 
          //__aspectRatio = VScale/HScale; 
          HScale = ((HScale * _currentScreenSize.Height)/VScale) * Defs.SCREEN_SIZE/100; 
          VScale = _currentScreenSize.Height * Defs.SCREEN_SIZE/100; 
         } 
        } 
        else if (VScale > _currentScreenSize.Height) {     // Long Edge is HEIGHT. For 100%, VScale = HEIGHT 
         //__aspectRatio = VScale/HScale; 
         HScale = ((HScale * _currentScreenSize.Height)/VScale) * Defs.SCREEN_SIZE/100; 
         VScale = _currentScreenSize.Height * Defs.SCREEN_SIZE/100; 
        } 
        else { 
         //Do nothing... Just set Zoom. 
         HScale = HScale * Defs.SCREEN_SIZE/100; 
         VScale = VScale * Defs.SCREEN_SIZE/100; 
        } 
       else 
        if (VScale > _currentScreenSize.Height) {     // Long Edge is HEIGHT. For 100%, VScale = HEIGHT 
         //__aspectRatio = VScale/HScale; 
         HScale = ((HScale * _currentScreenSize.Height)/VScale) * Defs.SCREEN_SIZE/100; 
         VScale = _currentScreenSize.Height * Defs.SCREEN_SIZE/100; 
        } 
        else if (HScale >= _currentScreenSize.Width) { // Long Edge is WIDTH. For 100%, HScale = WIDTH 
         VScale = ((VScale * _currentScreenSize.Width)/HScale) * Defs.SCREEN_SIZE/100; 
         HScale = _currentScreenSize.Width * Defs.SCREEN_SIZE/100; 
        } 
        else { 
         //Do nothing... Just set Zoom. 
         HScale = HScale * Defs.SCREEN_SIZE/100; 
         VScale = VScale * Defs.SCREEN_SIZE/100; 
        } 

       ////__aspectRatio = VScale/HScale; 
       //HScale = ((HScale * _currentScreenSize.Height)/VScale) * Defs.SCREEN_SIZE/100; 
       //VScale = _currentScreenSize.Height * Defs.SCREEN_SIZE/100; 
      } 

      Bitmap scaledBmp = GraphicsFactory.ResizeImage(
             __bmp, 
             Convert.ToInt32(HScale), 
             Convert.ToInt32(VScale)); 
6

你能避免使用一些技巧整數計算縱橫比(和使用雙打)..

// You have the new height, you need the new width 
int orgHeight = 1200; 
int orgWidth = 1920; 

int newHeight = 400; 
int newWidth = (newHeight * orgWidth)/orgHeight; // 640 

或...

// You have the new width, you need the new height. 
int orgWidth = 1920; 
int orgHeight = 1200; 

int newWidth = 800; 
int newHeight = (newWidth * orgHeight)/orgWidth; // 500 

以下示例將圖像調整爲任何所需的矩形(desWidth和desHeight)並將圖像居中那個矩形。

static Image ResizeImage(Image image, int desWidth, int desHeight) 
{ 
    int x, y, w, h; 

    if (image.Height > image.Width) 
    { 
     w = (image.Width * desHeight)/image.Height; 
     h = desHeight; 
     x = (desWidth - w)/2; 
     y = 0; 
    } 
    else 
    { 
     w = desWidth; 
     h = (image.Height * desWidth)/image.Width; 
     x = 0; 
     y = (desHeight - h)/2; 
    } 

    var bmp = new Bitmap(desWidth, desHeight); 

    using (Graphics g = Graphics.FromImage(bmp)) 
    { 
     g.CompositingQuality = CompositingQuality.HighQuality; 
     g.InterpolationMode = InterpolationMode.HighQualityBicubic; 
     g.DrawImage(image, x, y, w, h); 
    } 

    return bmp; 
} 
+0

我不認爲作者事先知道他需要什麼,因此需要比較長寬比。 – 2011-03-07 20:13:45

+0

嗯..它看起來像我知道哪個軸需要調整大小,他只是不知道如何計算縱橫比。我會擴大我的答案。 – 2011-03-07 22:11:55

+0

(不確定如何回覆答案:您的解決方案會使圖片成爲您提供的比例,因此會裁剪出不適合的圖片。例如,如果原始圖片爲500x500,並且您提供200x100的方法,則會我想在這種情況下,原來的海報會想要一個100x100的圖片,但是如果你想要裁剪的話,你的解決方案有很大的價值 – Jeremy 2011-05-20 02:52:32

12

如果圖像高度大於圖像寬度,Nathaniel發佈的解決方案實際上失敗。下面的示例產生了正確的結果:

private Size ResizeFit(Size originalSize, Size maxSize) 
{ 
    var widthRatio = (double)maxSize.Width/(double)originalSize.Width; 
    var heightRatio = (double) maxSize.Height/(double) originalSize.Height; 
    var minAspectRatio = Math.Min(widthRatio, heightRatio); 
    if (minAspectRatio > 1) 
     return originalSize; 
    return new Size((int)(originalSize.Width*minAspectRatio), (int)(originalSize.Height*minAspectRatio)); 
} 
+2

最後,一個有着理智的編碼技能的人;) – 2014-05-22 07:57:19

+1

+1應該是被接受的答案 – 2014-07-15 00:02:51

0

擬合到新尺寸的圖像,需要兩個操作:

  1. 調整大小 - 調整源圖像以適合恰好一個尺寸(寬度或高度 - 的一個具有較小比率)

  2. 裁剪 - 先前操作的結果到目標尺寸

這是一個小樣本:

private static Image Resize(Image img, int width, int height) 
    { 
     Bitmap b = new Bitmap(width, height); 
     using (Graphics g = Graphics.FromImage((Image)b)) 
     { 
      g.DrawImage(img, 0, 0, width, height); 
     } 

     return (Image)b; 
    } 

    public static Image Crop(Image image, int width, int height) 
    { 
     int cropx = image.Width > width ? image.Width/2 - width/2 : 0; 
     int cropy = image.Height > height ? image.Height/2 - height/2 : 0; 
     width = image.Width > width ? width : image.Width; 
     height = image.Height > height ? height : image.Height; 

     Rectangle cropRect = new Rectangle(cropx, cropy, width, height); 

     var target = new Bitmap(cropRect.Width, cropRect.Height); 

     using (Graphics g = Graphics.FromImage(target)) 
     { 
      g.DrawImage(image, new Rectangle(0, 0, target.Width, target.Height), cropRect, GraphicsUnit.Pixel); 
     } 

     return target; 
    } 

    public static Image FitToSize(Image image, int width, int height) 
    { 
     var wratio = 1.0 * image.Width/width; 
     var hratio = 1.0 * image.Height/height; 

     int wresize; 
     int hresize; 

     if (wratio >= hratio && wratio > 1) 
     { 
      wresize = (int)Math.Round((double)image.Width/hratio); 
      hresize = height; 

      image = Resize(image, wresize, hresize); 
      image = Crop(image, width, height); 
     } 
     else if (hratio >= wratio && hratio > 1) 
     { 
      hresize = (int)Math.Round((double)image.Height/wratio); 
      wresize = width; 

      image = Resize(image, wresize, hresize); 
      image = Crop(image, width, height); 
     } 
     return image; 

    } 
相關問題