【问题标题】:PHP GD crop & scale imagePHP GD 裁剪和缩放图像
【发布时间】:2011-11-16 06:44:59
【问题描述】:

我正在使用 jQuery 的 imgAreaSelect 插件来裁剪图像并保存缩略图以用于例如比率发生变化的情况。不幸的是,结果与我的预期相去甚远,而且我无法做到正确。图像会整体调整大小,而不是被裁剪。

这是测试示例:

<?php

/***
*
* $_GET returned values
*
* x1 = 0
* x2 = 400
* y1 = 66
* y2 = 258
* w = 400
* h = 192
* folder = widethumb
* filename = IMG_4591.jpg
* scale = 48
*
* Original image properties
*
* width = 600px
* height = 900px
*
***/

define('DOCROOT', realpath(dirname(__FILE__)).DIRECTORY_SEPARATOR);

extract($_GET);

$fn = $filename;
$filename = DOCROOT.$filename;

list($width, $height) = getimagesize($filename);

$src = imagecreatefromjpeg($filename);
$dst = imagecreatetruecolor($w, $h);
imagecopyresampled($dst, $src, 0, 0, (int) $x1, (int) $y1, (int) $w, (int) $h, $width, $height);

header('Content-Type: image/jpeg');
imagejpeg($dst);

我在这里错过了什么?

干杯!

【问题讨论】:

    标签: php jquery image crop


    【解决方案1】:

    这是一个函数,您可以将目标尺寸传递给它,然后从中心缩放和裁剪,保持纵横比,然后放大。这很容易通过响应式设计的图片元素来实现。如果您更改目标尺寸,只需删除输出的文件,这将在它们不存在的情况下重新创建图像。

        <?php
        function scaleCrop($src, $dest, $destW, $destH, $anchor){
            if(!file_exists($dest) && is_file($src) && is_readable($src)){
                $srcSize = getimagesize($src);
                $srcW = $srcSize[0];
                $srcH = $srcSize[1];
                $srcRatio = $srcW / $srcH;
                $destRatio = $destW / $destH;
                $img = (imagecreatefromjpeg($src));
                $imgNew = imagecreatetruecolor($destW, $destH);
    
                if ($srcRatio < $destRatio){
                    $scale = $srcW / $destW;
                }
                elseif($srcRatio >= $destRatio){
                    $scale = $srcH / $destH;
                }
                $srcX = ($srcW - ($destW * $scale)) / 2;
                if($anchor = 'middle'){
                    $srcY = ($srcH - ($destH * $scale)) / 2;
                }
                elseif($anchor = 'top'){
                    $srcY = 0;
                }
                elseif($anchor = 'bottom'){
                    $srcY = $srcH - ($destH * $scale);
                }
                if($srcX < 0){$srcX = 0;};
                if($srcY < 0){$srcY = 0;};
                imagecopyresampled($imgNew, $img, 0, 0, $srcX, $srcY, $destW, $destH, $destW * $scale, $destH * $scale);
                imagejpeg($imgNew, $dest, 70);
                imagedestroy($img);
                imagedestroy($imgNew);
            }
            return $dest;
        }
        ?>
    
    <img src="<?php echo scaleCrop('srcfolder/srcfile.jpg', 'destfolder/destfile.jpg', 320, 240, 'top'); ?>">
    

    【讨论】:

      【解决方案2】:

      来自 PHP 文档:

      bool imagecopyresampled ( resource $dst_image , resource $src_image , int $dst_x , int $dst_y , int $src_x , int $src_y , int $dst_w , int $dst_h , int $src_w , int $src_h )
      

      imagecopyresampled() 将一幅图像的矩形部分复制到另一幅图像,平滑地插入像素值,因此,特别是在减小图像尺寸时仍能保持很大的清晰度。

      换句话说,imagecopyresampled() 将从位置 (src_x,src_y) 的宽度为 src_w 和高度 src_h 的 src_image 中取出一个矩形区域,并将其放置在位置 (dst_x, dst_y)。

      因此,要获得您正在寻找的结果,您需要避免缩放。用于该用途:

      imagecopy($dst, $src, 0, 0, $x1, $y1, $w, $h);
      
      // this can also be done but is less efficient (over 10 times slower)
      imagecopyresampled($dst, $src, 0, 0, (int) $x1, (int) $y1, $w, $h, $w, $h);
      

      在这里,我们从源中获取与将其放入目标图像中相同大小的矩形。
      我刚刚测试了它,它工作得很好。

      更新: 我刚刚在我的测试服务器上再次尝试,它工作正常。我正在使用以下代码:

      $filename = "test.jpg";
      
      extract($_GET);
      
      $src = imagecreatefromjpeg($filename);
      $dst = imagecreatetruecolor($w, $h);
      imagecopy($dst, $src, 0, 0, $x1, $y1, $w, $h);
      
      // this is over 10 times slower, as we are only cropping we should use imagecopy
      //imagecopyresampled($dst, $src, 0, 0, $x1, $y1, $w, $h, $w, $h);
      
      header('Content-Type: image/jpeg');
      imagejpeg($dst);
      

      我这样称呼它:

      http://localserver/test/gd_crop.php?x1=906&y1=267&w=501&h=355

      性能更新
      由于我们没有调整大小,我们可以简单地使用imagecopy。我测量的 3 个函数的性能如下所示。

      imagecopyresampled    69ms
      imagecopyresized      5.5ms
      imagecopy             4.5ms
      

      因此,resampled 和其他两个函数之间存在 10 倍的速度差异。

      我终于想出了下面这行来代替imagecopyresampled函数,试试吧,我也更新了上面的代码清单:

      imagecopy($dst, $src, 0, 0, $x1, $y1, $w, $h);
      

      【讨论】:

      • 没用,显示的图片好像指向0,0,而不是0,66
      • 你能发布你更新的代码吗?由于它对我来说非常有效,请参阅我的答案的更新。
      • 解决了,在imagecopyresampled上使用$width$height,我会坚持下去,当我需要显示时,在img标签上定义widthheight它的规模。不是最好的解决方案,但也可以。我忘记的另一件事是我以较小的比例(2/3 或原始图像)显示带有jQuery 的图像,因此给了我奇怪的结果。谢谢,你的回答有帮助:)
      【解决方案3】:

      改用WideImage 库。

      这是我自己的裁剪功能:

      function createThumbnail($file, $cropX, $cropY, $cropWidth, $cropHeight, $desiredWidth, $desiredHeight, $shrink = false)
      {
          if(file_exists(MPS_ROOT_PATH . "$file") && $cropWidth && $cropHeight)
          {
              $source_path = MPS_ROOT_PATH . $file;
      
              list( $source_width, $source_height, $source_type ) = getimagesize( $source_path );
              switch ( $source_type )
              {
                  case IMAGETYPE_GIF:
                      $source_gdim = imagecreatefromgif( $source_path );
                      break;
      
                  case IMAGETYPE_JPEG:
                      $source_gdim = imagecreatefromjpeg( $source_path );
                      break;
      
                  case IMAGETYPE_PNG:
                      $source_gdim = imagecreatefrompng( $source_path );
                      break;
      
                  default:
                      return false;
              }
      
              if(!$desiredWidth)
              {
                  // Desired width not set, computing new width based on original 
                  // image's aspect ratio...
                  $desiredWidth = $cropWidth * ($desiredHeight / $cropHeight);
              }
      
              if(!$desiredHeight)
              {
                  // Desired height not set, computing new height based on original
                  // image's aspect ratio
                  $desiredHeight = $cropHeight * ($desiredWidth / $cropWidth);
              }
      
              if(!$desiredWidth || !$desiredHeight)
              {
                  // Desired height or width not set. 
                  // Halting image processing and returning file
                  return $file;
              }
      
              $source_aspect_ratio = $cropWidth / $cropHeight;
              $desired_aspect_ratio = $desiredWidth / $desiredHeight;
      
              if($shrink)
              {
                  // Shrink to fit flag set. Inverting computations to make image fit
                  // within the desired dimensions...
                  if($source_aspect_ratio > $desired_aspect_ratio)
                  {
                      // Source image is wider than desired aspect ratio, 
                      // setting thumbnail width to the desired width and the height 
                      // will be computed based on the original image's aspect ratio
                      $temp_width = $desiredWidth;
                      $temp_height = (int) ($desiredWidth / $source_aspect_ratio);
                  }
                  else
                  {
                      // Source image is taller than desired aspect ratio, 
                      // setting thumbnail height to the desired height and the width 
                      // will be computed based on the original image's aspect ratio
                      $temp_height = $desiredHeight;
                      $temp_width = (int) ($desiredHeight * $source_aspect_ratio);
                  }
              }
              // shrink to fit not set
              else
              {
                  if($source_aspect_ratio > $desired_aspect_ratio)
                  {
                      // Source image is wider than desired aspect ratio, 
                      // setting thumbnail height to the desired height to fill the 
                      // desired aspect ratio and the width will be computed based on 
                      // the original image's aspect ratio
                      $temp_height = $desiredHeight;
                      $temp_width = (int) ($desiredHeight * $source_aspect_ratio);
                  }
                  else
                  {
                      // Source image is taller than desired aspect ratio, 
                      // setting thumbnail width to the desired width to fill the 
                      // desired aspect ratio and the width will be computed based on 
                      // the original image's aspect ratio");
                      $temp_width = $desiredWidth;
                      $temp_height = (int) ($desiredWidth / $source_aspect_ratio);
                  }
              }
      
              $temp_gdim = imagecreatetruecolor($temp_width, $temp_height);
      
              // Copying a $cropWidth x $cropHeight image from the source 
              // file at ($cropX, $cropY) and resampling it to fit the temporary 
              // $temp_width x $temp_height thumbnail at (0, 0)
              imagecopyresampled(
                  $temp_gdim,
                  $source_gdim,
                  0, 0,
                  $cropX, $cropY,
                  $temp_width, $temp_height,
                  $cropWidth, $cropHeight
              );
      
              $x0 = ($desiredWidth - $temp_width) / 2;
              $y0 = ($desiredHeight - $temp_height) / 2;
              // Positioning the temporary $temp_width x $temp_height thumbnail in 
              // the center of the final $desiredWidth x $desiredHeight thumbnail...
              // Creating final thumbnail canvas at $desiredWidth x $desiredHeight
              $desired_gdim = imagecreatetruecolor($desiredWidth, $desiredHeight);
      
              $white = imagecolorallocate($desired_gdim, 255, 255, 255);
              imagefill($desired_gdim, 0, 0, $white);
              // Filling final thumbnail canvas with white
      
              // Copying a $temp_width x $temp_height image from the temporary 
              // thumbnail at (0, 0) and placing it in the final 
              // thumbnail at ($x0, $y0)
              imagecopy(
                  $desired_gdim,
                  $temp_gdim,
                  $x0, $y0,
                  0, 0,
                  $temp_width, $temp_height
              );
      
              $pathInfo = pathinfo($file);
              $thumbFile = "images/thumbs/thumb_" . basename($pathInfo["filename"]) . ".jpg";
      
              if(imagejpeg($desired_gdim, MPS_ROOT_PATH . $thumbFile, 80))
              {
                  return $thumbFile;
              }
              else
              {
                  return 1;
              }
          }
          else
          {
              echo "Image File Does not exist or Invalid crop parameters!";
              return false;
          }
      }
      

      【讨论】:

      • 不需要 - PHP 可以在内部执行此操作。请在发布您的答案之前进行一些研究。
      • @JamWaffles:我知道我在说什么。我知道 PHP 可以自己做到这一点,我也一直在使用 GD2 来裁剪和调整图像大小,但是使用库会减轻开发人员的负担,因此开发人员可以专注于脚本的更大部分。
      • 确实如此,但是如果开发人员只需要整个库中的一个函数,为什么还要添加额外的膨胀?如果他们以后需要重用或扩展它,PHP 有类是有原因的 :-)
      • 嗯,我想我明白你来自哪里。只是我一直处于这种情况,我的截止日期很紧,我不得不花几天时间开发我的裁剪功能,它有 30 行左右,结果发现它可以使用库在 1 行中完成。 =) @OP:我稍后会发布我的裁剪功能。坚持住
      【解决方案4】:

      你为什么不考虑使用 imagemagik;它非常适合图像处理和裁剪只是使用cropImage($width, $height, $x, $y);的一个简单案例;

      【讨论】:

      • 因为我的客户的主机没有安装,客户拒绝更换主机和托管公司...最好不要说:)
      • 还有PHP内置的图像处理功能。
      猜你喜欢
      • 1970-01-01
      • 2017-06-18
      • 1970-01-01
      • 2012-07-21
      • 2010-11-03
      • 1970-01-01
      • 2015-04-20
      • 1970-01-01
      • 2014-06-03
      相关资源
      最近更新 更多