【问题标题】:How to "smart resize" a displayed image to original aspect ratio如何将显示的图像“智能调整大小”为原始纵横比
【发布时间】:2011-03-01 19:52:25
【问题描述】:

我有一个应用程序,最终用户可以在其中调整设计器中的图像大小和位置。由于规范要求将图像“拉伸”到包含控件,因此最终用户可能会得到一个尴尬的拉伸图像。

为了帮助用户调整图像大小,我正在考虑实现一个智能调整器功能,该功能允许用户轻松修复图片的纵横比,使其不再显得拉伸。

解决这个问题的快速方法是实际提供两个选项:1)从宽度缩放 2)从高度缩放。用户选择方法,算法使用原始纵横比调整图片大小。例如:图片在设计器上显示为 200x200,但原始图像为 1024x768 像素。用户选择“Smart Size from width”,新尺寸变为~200x150,因为原始纵横比为~1.333

没关系,但是我怎样才能使算法更智能,并且不通过询问重新计算应该基于哪个维度来打扰用户呢?

【问题讨论】:

    标签: algorithm image image-processing aspect-ratio


    【解决方案1】:

    如果我正确解释了您的规范,您希望得到的结果不大于最终用户最初布局的结果;您希望两个维度中的一个缩小,而另一个保持不变。换句话说,新的尺寸应该在一个方向上填充设计者空间,同时在另一个方向上缩短尺寸以保持原来的纵横比。

    original_ratio = original_width / original_height
    designer_ratio = designer_width / designer_height
    if original_ratio > designer_ratio
        designer_height = designer_width / original_ratio
    else
        designer_width = designer_height * original_ratio
    

    您通常会使用整数坐标,但产生上述比率的除法需要是浮点数。这是对公式的重新排列,以使整数更友好。确保您的整数具有处理最大宽度*高度的范围。

    if original_width * designer_height > designer_width * original_height
        designer_height = (designer_width * original_height) / original_width
    else
        designer_width = (designer_height * original_width) / original_height
    

    【讨论】:

    • 是的,需要扩展规范以定义智能调整大小的实际作用。这个算法听起来很合理。我试试看。
    【解决方案2】:

    这是我在处理这个问题时想出的一个解决方案。结果非常简短直接 imo,只是想分享它。

    方便的“公式”:ratio = W / H W = H * ratio H = W / ratio

    1. 计算比率。
    2. 如果要将宽度设置为新的尺寸宽度(允许的最大宽度),请计算图像的高度。
    3. 如果要将高度设置为新的尺寸高度(允许的最大高度),请计算图像的宽度。
    4. 查看两种尺寸中的哪一种不会覆盖任何尺寸的最大尺寸。如果比率不是 1,则其中一个永远是错误的,一个永远是正确的。

    在 Javascript 中

    // Returns array with new width and height
    function proportionalScale(originalSize, newSize)
    {
        var ratio = originalSize[0] / originalSize[1];
    
        var maximizedToWidth = [newSize[0], newSize[0] / ratio];
        var maximizedToHeight = [newSize[1] * ratio, newSize[1]];
    
        if (maximizedToWidth[1] > newSize[1]) { return maximizedToHeight; }
        else { return maximizedToWidth; }
    }
    

    originalSizenewSize 是一个数组 [0] = width, [1] = height

    【讨论】:

      【解决方案3】:

      我也想知道这一点,我看到的只是缩放宽度或高度的无数示例,但可能会使另一个溢出。

      • 无需循环即可调整宽度和高度
      • 不超过图片的原始尺寸

      .

      private void ResizeImage(Image img, double maxWidth, double maxHeight)
      {
        double srcWidth = img.Source.Width;
        double srcHeight = img.Source.Height;
      
        double resizeWidth = srcWidth;
        double resizeHeight = srcHeight;
      
        double aspect = resizeWidth / resizeHeight;
      
        if (resizeWidth > maxWidth)
        {
          resizeWidth = maxWidth;
          resizeHeight = resizeWidth / aspect;
        }
        if (resizeHeight > maxHeight)
        {
          aspect = resizeWidth / resizeHeight;
          resizeHeight = maxHeight;
          resizeWidth = resizeHeight * aspect;
        }
      
        img.Width = resizeWidth;
        img.Height = resizeHeight;
      }
      

      【讨论】:

        【解决方案4】:

        计算两种变体的新尺寸(“按宽度缩放”和“按高度缩放”),然后使用适合显示的那个。

        或者,您也可以计算“边界框”的纵横比,并将其与原始图像的纵横比进行比较。根据哪个纵横比更大,需要缩放高度或宽度。

        您还可以限制调整大小的过程,以便在所有情况下都完成“按宽度缩放”。然后,要改变图像的大小,用户总是必须改变它的宽度。高度将始终自动调整。

        【讨论】:

        • 我一直在思考这些问题,但是当用户可以任意调整图像的大小和位置时,你如何确定什么是太宽或太高?
        • @Paul:不是限制在200x200吗?当前的 smart-size 函数的极限来自哪里?
        • 我们越来越接近了。限制是由用户通过操纵图像大小隐式设置的。请参阅下面我对 khnle 的回复。
        • 因此,如果用户调整了图像的大小,您是否可以采用由此创建的新限制并测试两种调整大小方法中的哪一种适用于这些限制? (此外,我在答案中编辑了更多想法..)
        【解决方案5】:

        接受上面的建议,使其在最大高度/宽度范围内放大/缩小。这里是它的 python 代码,还添加了对旋转物体的支持,同时保持在限制范围内:

        def _resize(图像,尺寸,旋转=无): """ 将图像调整为尽可能接近指定尺寸。图像是一个 django 图像模型字段。

            Will both scale up and down the image to meet this while keeping the proportions
            in width and height
        
        """
        
        if image and os.path.isfile(image.path):
        
            im = pil.open(image.path)
            logging.debug('resizing image from %s x %s --> %s x %s ' % (im.size[0], im.size[1], dimensions[0], dimensions[1]))
        
            if rotate:
                logging.debug('first rotating image %s' % rotate)
                im = im.rotate(90)
        
            srcWidth = Decimal(im.size[0])
            srcHeight = Decimal(im.size[1])
        
            resizeWidth = srcWidth
            resizeHeight = srcHeight
        
            aspect = resizeWidth / resizeHeight # Decimal
        
            logging.debug('resize aspect is %s' % aspect)
        
            if resizeWidth > dimensions[0] or resizeHeight > dimensions[1]:
                # if width or height is bigger we need to shrink things
                if resizeWidth > dimensions[0]:
                    resizeWidth = Decimal(dimensions[0])
                    resizeHeight = resizeWidth / aspect
        
                if resizeHeight > dimensions[1] :
                    aspect = resizeWidth / resizeHeight
                    resizeHeight = Decimal(dimensions[1])
                    resizeWidth = resizeHeight * aspect
        
            else:
                # if both width and height are smaller we need to increase size
                if resizeWidth < dimensions[0]:
                    resizeWidth = Decimal(dimensions[0])
                    resizeHeight = resizeWidth / aspect
        
                if resizeHeight > dimensions[1] :
                    aspect = resizeWidth / resizeHeight
                    resizeHeight = Decimal(dimensions[1])
                    resizeWidth = resizeHeight * aspect
        
            im = im.resize((resizeWidth, resizeHeight), pil.ANTIALIAS)
        
            logging.debug('resized image to %s %s' % im.size)
            im.save(image.path)
        
        else:
            # no action, due to no image or no image in path
            pass
        
        return image
        

        【讨论】:

          【解决方案6】:

          因为您希望在窗口中(即设计器中的区域)尽可能多地显示缩放后的图像(原始图像),所以您将采用原始图像的宽度或高度中较大的一个,然后缩放到200。伪代码(宽度,高度是原始尺寸):

          if (width > height) {
              scaledWidth = 200;
              scaledHeight = (height * 200) / width;
          } else {
              scaledHeight = 200;
              scaledWidth = (width * 200) / height;
          }
          

          【讨论】:

          • 没有。我希望图像的大小尽可能接近用户布置的内容。最后,其中一个维度将保持不变。
          【解决方案7】:

          这是我的解决方案,

          a = 方面 sw = 原始图像宽度 sh = 原始图像高度 dw = 请求的最大宽度 dh = 请求的最大高度

          sw 和 sh 将包含最终调整大小的值

          代码是 PHP:

          $a = $sw / $sh;
          
          if($a > 1){
              //  wider image
              if($sw != $dw){
                  $rt = $dw / $sw;
                  $sw = $sw * $rt;
                  $sh = $sh * $rt;
              }
          
              if($sh > $dh){
                  $rt = $dh / $sh;
                  $sw = $sw * $rt;
                  $sh = $sh * $rt;
              }
          }else{
              //  taller image
              if($sh != $dh){
                  $rt = $dh / $sh;
                  $sh = $sh * $rt;
                  $sw = $sw * $rt;
              }
          
              if($sw > $dw){
                  $rt = $dw / $sw;
                  $sh = $sh * $rt;
                  $sw = $sw * $rt;
              }
          }
          

          【讨论】:

            【解决方案8】:

            我基于https://stackoverflow.com/a/5654847/1055015在javascript中缩小和增长大小的解决方案

            var scale =  function (srcWidth, srcHeight, maxWidth, maxHeight) {
            
                  let resizeWidth  = srcWidth;
                  let resizeHeight = srcHeight;
            
                  let aspect = resizeWidth / resizeHeight;
                  let scaleX = maxWidth / srcWidth;
                  let scaleY = maxHeight / srcHeight;
                  let scale  = Math.min(scaleX, scaleY);
            
                  resizeWidth *= scale;
                  resizeHeight *= scale;
            
                  if (resizeWidth > maxWidth) {
                    resizeWidth  = maxWidth;
                    resizeHeight = resizeWidth / aspect;
                  }
            
                  if (resizeHeight > maxHeight) {
                    aspect       = resizeWidth / resizeHeight;
                    resizeHeight = maxHeight;
                    resizeWidth  = resizeHeight * aspect;
                  }
            
                  return {
                    width : resizeWidth,
                    height: resizeHeight,
                  };
                }
            

            【讨论】:

              【解决方案9】:

              您只需要计算出两个维度所需的比例,然后取 2 中的较小者。

              【讨论】:

                【解决方案10】:

                我使用这种方式将图像调整为 FHD 方式

                if ( width >= height) {
                  var original_ratio = width / height
                  new_width = 1080 * original_ratio
                  console.log("new new_width = " + Math.round(new_width) );
                  console.log("new new_height = 1080");
                } else {
                  var original_ratio =  height / width
                  new_height = 1080 * original_ratio
                  console.log("new new_height = " + Math.round(new_height) );
                  console.log("new new_width = 1080");
                }
                

                您可以将 1080 更改为新尺寸。

                我希望它至少对某人有用。

                【讨论】:

                  猜你喜欢
                  • 2013-02-10
                  • 2017-08-10
                  • 2014-06-15
                  • 1970-01-01
                  • 2013-06-26
                  • 2012-04-15
                  相关资源
                  最近更新 更多