调整图像大小以适合边框
c#
image-manipulation
image-processing
7
0

这是一个简单的问题,但由于某种原因,我今天无法解决。

我需要将图像调整为适合边框的最大可能尺寸,同时保持宽高比。

基本上,我正在寻找填充此功能的代码:

void CalcNewDimensions(ref int w, ref int h, int MaxWidth, int MaxHeight);

其中w&h是原始高度和宽度(输入),新的高度和宽度(输出)以及MaxWidth和MaxHeight定义了图像必须适合的边界框。

参考资料:
Stack Overflow
收藏
评论
共 7 个回答
高赞 时间 活跃

非常简单。 :)问题是找到一个需要乘以宽度和高度的因素。解决方案是尝试使用其中一种,如果不合适,则使用另一种。所以...

private float ScaleFactor(Rectangle outer, Rectangle inner)
{
    float factor = (float)outer.Height / (float)inner.Height;
    if ((float)inner.Width * factor > outer.Width) // Switch!
        factor = (float)outer.Width / (float)inner.Width;
    return factor;
}

要将图片(pctRect)适配到窗口(wndRect),请像这样调用

float factor=ScaleFactor(wndRect, pctRect); // Outer, inner
RectangleF resultRect=new RectangleF(0,0,pctRect.Width*factor,pctRect.Height*Factor)
收藏
评论

查找哪个较小: MaxWidth / wMaxHeight / h然后将wh乘以该数字

说明:

您需要找到使图像合适的比例因子。

要找到宽度的比例因子s ,则s必须满足以下条件: s * w = MaxWidth 。因此,缩放比例为MaxWidth / w

高度也一样。

需要最大缩放比例( s较小)的是必须缩放整个图像的因素。

收藏
评论

尝试了沃伦先生的代码,但未产生可靠的结果。

例如,

ExpandToBound(new Size(640,480), new Size(66, 999)).Dump();
// {Width=66, Height=49}

ExpandToBound(new Size(640,480), new Size(999,50)).Dump();
// {Width=66, Height=50}

您可以看到,高度= 49,高度= 50。

这是我的(沃伦先生代码的基础版本),没有任何差异和轻微重构:

// Passing null for either maxWidth or maxHeight maintains aspect ratio while
//        the other non-null parameter is guaranteed to be constrained to
//        its maximum value.
//
//  Example: maxHeight = 50, maxWidth = null
//    Constrain the height to a maximum value of 50, respecting the aspect
//    ratio, to any width.
//
//  Example: maxHeight = 100, maxWidth = 90
//    Constrain the height to a maximum of 100 and width to a maximum of 90
//    whichever comes first.
//
private static Size ScaleSize( Size from, int? maxWidth, int? maxHeight )
{
   if ( !maxWidth.HasValue && !maxHeight.HasValue ) throw new ArgumentException( "At least one scale factor (toWidth or toHeight) must not be null." );
   if ( from.Height == 0 || from.Width == 0 ) throw new ArgumentException( "Cannot scale size from zero." );

   double? widthScale = null;
   double? heightScale = null;

   if ( maxWidth.HasValue )
   {
       widthScale = maxWidth.Value / (double)from.Width;
   }
   if ( maxHeight.HasValue )
   {
       heightScale = maxHeight.Value / (double)from.Height;
   }

   double scale = Math.Min( (double)(widthScale ?? heightScale),
                            (double)(heightScale ?? widthScale) );

   return new Size( (int)Math.Floor( from.Width * scale ), (int)Math.Ceiling( from.Height * scale ) );
}
收藏
评论

要执行宽高比填充而不是宽高比拟合,请改用较大的比例。也就是说,将Matt的代码从Math.Min更改为Math.Max。

(宽高比填充不使边界框为空,但可以将某些图像置于边界外,而宽高比拟合则不使图像超出边界,但可以使某些边界框为空。)

收藏
评论

以下代码可产生更准确的结果:

    public static Size CalculateResizeToFit(Size imageSize, Size boxSize)
    {
        // TODO: Check for arguments (for null and <=0)
        var widthScale = boxSize.Width / (double)imageSize.Width;
        var heightScale = boxSize.Height / (double)imageSize.Height;
        var scale = Math.Min(widthScale, heightScale);
        return new Size(
            (int)Math.Round((imageSize.Width * scale)),
            (int)Math.Round((imageSize.Height * scale))
            );
    }
收藏
评论

Python代码,但也许它将为您指明正确的方向:

def fit_within_box(box_width, box_height, width, height):
    """
    Returns a tuple (new_width, new_height) which has the property
    that it fits within box_width and box_height and has (close to)
    the same aspect ratio as the original size
    """
    new_width, new_height = width, height
    aspect_ratio = float(width) / float(height)

    if new_width > box_width:
        new_width = box_width
        new_height = int(new_width / aspect_ratio)

    if new_height > box_height:
        new_height = box_height
        new_width = int(new_height * aspect_ratio)

    return (new_width, new_height)
收藏
评论

基于Eric的建议,我将执行以下操作:

private static Size ExpandToBound(Size image, Size boundingBox)
{       
    double widthScale = 0, heightScale = 0;
    if (image.Width != 0)
        widthScale = (double)boundingBox.Width / (double)image.Width;
    if (image.Height != 0)
        heightScale = (double)boundingBox.Height / (double)image.Height;                

    double scale = Math.Min(widthScale, heightScale);

    Size result = new Size((int)(image.Width * scale), 
                        (int)(image.Height * scale));
    return result;
}

我可能在转换时有些过分,但我只是想保持计算的准确性。

收藏
评论
新手导航
  • 社区规范
  • 提出问题
  • 进行投票
  • 个人资料
  • 优化问题
  • 回答问题

关于我们

常见问题

内容许可

联系我们

@2020 AskGo
京ICP备20001863号