С#: как изменить размер изображения пропорционально максимальной высоте

Мне нужно пропорционально изменить размер изображения без изменения соотношения сторон. У меня есть код для изменения размера с фиксированной высотой и шириной, но мне нужно пропорционально изменить размер изображения с максимальной высотой (скажем, 600 пикселей). Как я могу изменить код в соответствии с моими требованиями?

public static void Main()
{
  var image = Image.FromFile(@"c:\logo.png");
  var newImage = ScaleImage(image, 300, 400);
  newImage.Save(@"c:\test.png", ImageFormat.Png);
}

public static Image ScaleImage(Image image, int maxWidth, int maxHeight)
 {
  var ratioX = (double)maxWidth / image.Width;
  var ratioY = (double)maxHeight / image.Height;
  var ratio = Math.Min(ratioX, ratioY);

  var newWidth = (int)(image.Width * ratio);
  var newHeight = (int)(image.Height * ratio);

  var newImage = new Bitmap(newWidth, newHeight);
  Graphics.FromImage(newImage).DrawImage(image, 0, 0, newWidth, newHeight);
  return newImage;
}

Пожалуйста, поделитесь своими ценными мыслями.


person user735647    schedule 26.04.2012    source источник
comment
В чем проблема с этим кодом?   -  person Likurg    schedule 26.04.2012
comment
при всем уважении, пожалуйста, выполните мое требование. Этот код использует максимальную высоту и максимальную ширину, тогда как мне нужно пропорционально изменить размер изображения, сохраняя только высоту до максимального числа (скажем, 600).   -  person user735647    schedule 26.04.2012
comment
Я не знаю, в чем проблема, но, если я не ошибаюсь, ваш код изменяет размер изображения без изменения соотношения сторон. Можете ли вы добавить пример того, что вы ожидаете?   -  person Remko Jansen    schedule 26.04.2012
comment
используйте ratioY вместо ratio для вычисления newWidth и newHeigth   -  person axl g    schedule 26.04.2012
comment
@remko: Да, вы абсолютно правы, но в моем коде я передаю фиксированную высоту и ширину методу ScaleImage. Что мне действительно нужно, так это передать размер с фиксированной высотой, но пропорциональной шириной. Можно ли этого добиться?   -  person user735647    schedule 26.04.2012


Ответы (4)


Это почти кажется легким, и я чувствую, что что-то упускаю. В любом случае, разве это не поможет?

public static Image ScaleImage(Image image, int maxHeight) 
{ 
    var ratio = (double)maxHeight / image.Height; 

    var newWidth = (int)(image.Width * ratio); 
    var newHeight = (int)(image.Height * ratio); 

    var newImage = new Bitmap(newWidth, newHeight); 
    using (var g = Graphics.FromImage(newImage))
    {
        g.DrawImage(image, 0, 0, newWidth, newHeight); 
    }
    return newImage; 
} 
person gwiazdorrr    schedule 26.04.2012
comment
Большое спасибо. Позвольте мне попробовать. - person user735647; 26.04.2012
comment
Что мне нужно добавить, чтобы предотвратить масштабирование изображения, которое соответствует максимальной высоте или максимальной ширине, и если одна из сторон больше, просто уменьшите размер, пока он не будет соответствовать необходимой области, сохраняя пропорции. - person Idan Shechter; 27.07.2016

Используйте следующую функцию

public Bitmap ProportionallyResizeBitmapByHeight(Bitmap imgToResize, int height)
{
  int sourceWidth = imgToResize.Width;
  int sourceHeight = imgToResize.Height;

  float scale = 0;

  scale = (height / (float)sourceHeight);

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

  Bitmap result = new Bitmap(destWidth, destHeight);
  result.SetResolution(imgToResize.HorizontalResolution, imgToResize.VerticalResolution);
  Graphics g = Graphics.FromImage(result);
  g.DrawImage(imgToResize, 0, 0, destWidth, destHeight);
  g.Dispose();

  return result;
}
person Imran Rizvi    schedule 26.04.2012
comment
@Имран Большое спасибо. Позвольте мне попробовать. - person user735647; 26.04.2012

Хорошо, продумывая процесс: если у вас есть изображение размером 800 x 600 и вы хотите изменить его размер до высоты newWidth x 400 (плюс то, что будет соответствующим newWidth), вы получите соотношение, разделив newHeight (maxHeight в вашем случай) с 600 и умножьте 800 на это соотношение, верно?

Итак, в этом случае вам нужно изменить maxWidth и maxHeight на необязательные параметры (скажем, 800 на 600), чтобы придать себе динамизма и получить следующее:

public static Image ScaleImage(Image image, int maxWidth = 800, int maxHeight = 600)
 {

  int newWidth;
  int newHeight;
  double ratio = image.Height / image.Width;

  if(maxHeight != 600) {

     newWidth = image.Width * ratio;
     newHeight = maxHeight;

  }   

  Bitmap newImage = new Bitmap(newWidth, newHeight);
  Graphics.FromImage(newImage).DrawImage(image, 0, 0, newWidth, newHeight);
  return newImage;
}

Надеюсь, это поможет. Я не проверял это, но я переписал свой код VB, так что якобы все должно быть в порядке...

Здесь также есть метод ResizeStream: http://forums.asp.net/t/1576697.aspx/1, которые могут оказаться полезными. Если вы хотите сохранить качество изображения, вы можете использовать переменные CompositingQuality, SmoothingMode и т. д.

person army    schedule 26.04.2012
comment
Большое спасибо. Позвольте мне попробовать. - person user735647; 26.04.2012
comment
Нет проблем. Я надеюсь, что это помогает. Дай мне знать, если наткнешься на риф. Еще одна вещь: это основано на максимальной высоте, поэтому вы можете также проверить еще, если (maxWidth != 800) и соответственно изменить newWidth и newHeight. Но ссылка, которую я включил, очень удобна в любом случае. - person army; 26.04.2012

100% сработало

   private static BitmapFrame CreateResizedImage(ImageSource source, int Max_width, int Max_height, int margin)
{
    float scaleHeight = (float)Max_width / (float)source.Height;
    float scaleWidth = (float)Max_height / (float)source.Width;
    float scale = Math.Min(scaleHeight, scaleWidth);

     int width = (int)(source.Width * scale);
     int height = (int)(source.Height * scale);


    var rect = new Rect(margin, margin, width - margin * 2, height - margin * 2);

    var group = new DrawingGroup();
    RenderOptions.SetBitmapScalingMode(group, BitmapScalingMode.HighQuality);
    group.Children.Add(new ImageDrawing(source, rect));

    var drawingVisual = new DrawingVisual();
    using (var drawingContext = drawingVisual.RenderOpen())
        drawingContext.DrawDrawing(group);

    var resizedImage = new RenderTargetBitmap(
        width, height,         // Resized dimensions
        96, 96,                // Default DPI values
        PixelFormats.Default); // Default pixel format
    resizedImage.Render(drawingVisual);

    return BitmapFrame.Create(resizedImage);
}


//--------Main------------//

  BitmapImage imageSource = (BitmapImage)ImagePreview.Source;
  var NewImage= CreateResizedImage(imageSource , 300, 300, 0);
person Zk Wave    schedule 05.10.2017