【问题标题】:Resize image without distortion keeping aspect ratio then crop excess using WideImage调整图像大小而不失真,保持纵横比,然后使用 WideImage 裁剪多余的图像
【发布时间】:2011-09-15 09:42:53
【问题描述】:

我正在处理的网站上有一个区域,该区域将显示从外部来源提取的用户个人资料图像(因此无法控制其原始大小)。

我要做的是拍摄一张图片(在此示例中为 1000px x 800px 并将其大小调整为 200px x 150px。显然这存在纵横比差异。

我想要做的是调整原始图像的大小而不失真,在这种情况下会产生200px x 160px 图像。然后我想要做的是从边缘裁剪任何多余的部分以产生正确的图像尺寸。因此,在这种情况下,从图像的顶部和底部裁剪 5px,最终生成 200px x 150px

我目前有WideImage 库,并希望使用它。我在 SO 上看到了几个类似的问题,但我不能说完全符合我的目标。

【问题讨论】:

  • 您的问题是什么?请停止在标题中写标签。这不是留言板;我们有自己的语义帖子标记系统。
  • 纵横比背后的数学不应该很复杂,因为WideImageresize() 方法已经完成了数学运算。我不确定是否应该将$fit 设置为insideoutside。另外,如果crop('center', 'center', 200, 150)center-100, center-75center, center 作为左上角 角,我无法从文档中理解。
  • 我不确定 API 参考中的操作方法,是否可以直接通过 API 本身进行,或者是否需要事先计算(我不确定该怎么做,因为我'以前从来没有这样做过)。

标签: php image-resizing


【解决方案1】:

我尝试了您的所有解决方案,但每次都得出奇怪的数字。所以,这就是我的计算方式。

基本比例公式:a/b=x/y -> ay = bx 然后求解未知值。 所以,让我们把它放到代码中。

此函数假定您已将图像打开到变量中。如果传递路径,则必须在函数中打开图像,进行数学运算,将其杀死,返回值,然后在调整图像大小时再次打开图像,效率低下...

function resize_values($image){
    #for the purpose of this example, we'll set this here
    #to make this function more powerful, i'd pass these 
    #to the function on the fly
    $maxWidth = 200; 
    $maxHeight = 200;

    #get the size of the image you're resizing.
    $origHeight = imagesy($image);
    $origWidth = imagesx($image);

    #check for longest side, we'll be seeing that to the max value above
    if($origHeight > $origWidth){ #if height is more than width
         $newWidth = ($maxHeight * $origWidth) / $origHeight;

         $retval = array(width => $newWidth, height => $maxHeight);
    }else{
         $newHeight= ($maxWidth * $origHeight) / $origWidth;

         $retval = array(width => $maxWidth, height => $newHeight);
    }
return $retval;
}

显然,上面的函数返回一个数组。您可以将公式应用到您正在处理的任何脚本中。事实证明,这是适合这项工作的正确公式。所以......取决于你是否使用它。稍后!

【讨论】:

    【解决方案2】:
    //Following code for keeping aspect ratio
    
    $srcWidth=1000;
    $srcHeight=800;
    
    $targetWidth=200;
    $targetHeight=150;
    
    $diff=0;
    //get difference
    
    if( $srcWidth > $srcHeight ) // 1000 > 800
    {
        $diff = $srcWidth - $srcHeight; // 1000 - 800 = 200
        $diff = ($diff / $srcWidth) * 100; // ( 200 / 1000 ) * 100 = 20
    }
    else
    {
        $diff = $srcHeight - $srcWidth;
        $diff = ($diff / $srcHeight)*100;
    }
    
    if( $targetWidth > $targetHeight)
    {
        $targetHeight = (( $targetHeight * $diff ) / 100) - $targetWidth; // (( 200 * 20 ) /  100) - 200 = 160
    }
    else
    {
        $targetWidth = (( $targetWidth * $diff ) / 100) - $targetHeight;
    }
    

    【讨论】:

      【解决方案3】:

      答案 #1(已编辑)

      查看thisthis 之后,您可能需要执行以下操作:

      $img->resize(200, 150, 'outside')->crop("center", "center", 200, 150);
      

      在调整大小时,它会调整图像的大小,使其完全适合框(框 = 200x150)或其中一个尺寸适合而另一个超出框。裁剪时,框外出血的图像部分将被修剪。指定center 智能坐标意味着将删除顶部+底部或左侧+右侧部分。

      回答 #2

      如果您在计算要裁剪的内容时遇到问题,试试这个:

      <?php
      $target_wide = 200;
      $target_tall = 150;
      
      $test_case = array(
          array(1000, 800),
          array(800, 1000),
          array(1000, 750), // perfect fit
          array(750, 1000)
      );
      
      foreach($test_case as $test) {
          list(
              $source_wide,
              $source_tall
          ) = $test;
          $source_aspect_ratio = $source_wide / $source_tall;
          $target_aspect_ratio = $target_wide / $target_tall;
          if ($source_aspect_ratio > $target_aspect_ratio)
          {
              $output_tall = $target_tall;
              $output_wide = (int) ($target_tall * $source_aspect_ratio);
          }
          else
          {
              $output_wide = $target_wide;
              $output_tall = (int) ($target_wide / $source_aspect_ratio);
          }
          $output_crop_hori = (int) (($output_wide - $target_wide) / 2);
          $output_crop_vert = (int) (($output_tall - $target_tall) / 2);
          var_dump($source_wide, $source_tall, $output_wide, $output_tall, $output_crop_hori, $output_crop_vert);
          echo PHP_EOL;
      }
      

      输出:

      int(1000)
      int(800)
      int(200)
      int(160)
      int(0)
      int(5)
      
      int(800)
      int(1000)
      int(200)
      int(250)
      int(0)
      int(50)
      
      int(1000)
      int(750)
      int(200)
      int(150)
      int(0)
      int(0)
      
      int(750)
      int(1000)
      int(200)
      int(266)
      int(0)
      int(58)
      

      【讨论】:

      • 关于“Answer #1”(实际上是“Answer #2”:))...crop() 的前两个参数是 $left 和 @ 987654329@。我相信center 作为$left$right 将指定裁剪图像的角落在图像的中心,即,如果他有200x160 图像,crop('center', 'center', 200, 150) 将与crop(100, 80, 200, 150) 相同,而不是@987654335 @。不过,这应该进行测试。附:一个小时前我已经写过这个方法了……
      • @binary: 是的,答案是 #2 :) 前两个参数是左和 top,而不是右。因此(0, 5, 200, 150)('center', 'center', 200, 150) 是等价的;指定诸如“中心”之类的常量可以让您不必自己进行计算。
      • 刚刚测试过,$left$right 确实应该只是center
      【解决方案4】:

      你可以试试:

      $img->resize(200, 150, 'outside')->crop('center', 'middle', 200, 150);
      

      一些用户发布他们的计算版本...这也是我的版本:

      $sourceWidth = 1000;
      $sourceHeight = 250;
      
      $targetWidth = 200;
      $targetHeight = 150;
      
      $sourceRatio = $sourceWidth / $sourceHeight;
      $targetRatio = $targetWidth / $targetHeight;
      
      if ( $sourceRatio < $targetRatio ) {
          $scale = $sourceWidth / $targetWidth;
      } else {
          $scale = $sourceHeight / $targetHeight;
      }
      
      $resizeWidth = (int)($sourceWidth / $scale);
      $resizeHeight = (int)($sourceHeight / $scale);
      
      $cropLeft = (int)(($resizeWidth - $targetWidth) / 2);
      $cropTop = (int)(($resizeHeight - $targetHeight) / 2);
      
      var_dump($resizeWidth, $resizeHeight, $cropLeft, $cropTop);
      

      【讨论】:

      • 谢谢你,我会试试看,让你知道我的进展情况
      • @Salman A,你说得对,应该使用outside,而不是inside。在crop() 中使用center 作为$left$top 参数的值也是正确的。
      【解决方案5】:

      这就是你可以计算作物大小的方法:

      $src_width = 1000;
      $src_height = 500;
      $src_ratio = $src_width/$src_height;
      
      $width = 200;
      $height = 150;
      $ratio = $width/$height;
      
      $crop_height = 0;
      $crop_width = 0;
      
      if ($src_height > $src_width)
      {
          $new_height = $width/$src_ratio;
          $crop_height = $new_height-$height;
      }
      else
      {
          $new_width = $height*$src_ratio;
          $crop_width = $new_width-$width;
      }
      
      print 'Crop height: '.$crop_height.PHP_EOL
            .'Crop width: '.$crop_width;
      

      【讨论】:

      • 我认为还是有问题...尝试将 $src_height 设置为 1500。我得到的是 200 x 133.333 而不是 200 x 300。
      • @binaryLV,它是计算裁剪,而不是新的宽度和高度。使用$src_height = 1500; 结果将是:Crop height: -16.6(6)
      • 我说的是$new_width$new_heightcrop height 怎么可能是负面的?裁剪角的位置应在 in 图像中。
      • @binaryLV,它只是计算作物大小的临时变量。但你是对的,在一个地方 * 应该替换为 / - 复制粘贴错误:) 谢谢。
      猜你喜欢
      • 2014-03-02
      • 2013-10-05
      • 2013-06-26
      • 2012-04-15
      • 2012-11-23
      • 1970-01-01
      相关资源
      最近更新 更多