2011-09-13 64 views
1

我使用jQuery的imgAreaSelect插件来裁剪图像并保存缩略图以便在例如比例发生变化的情况下使用。令人遗憾的是,结果与我所期望的并不相符,而我无法做到。图像被整体调整大小而不是被裁剪。PHP GD作物和比例尺图像

这里的测试例子:

<?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); 

什么我mising这里?

干杯!

回答

5

从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_image的宽度src_w和高度src_h的位置(src_x,src_y)取一个矩形区域,并将其放置在宽度为dst_w的dst_image和位置为(dst_x的高度为dst_h的矩形区域中,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 

所以重新采样和其他两个函数之间存在10个速度差的顺序。

我终于想出了下面一行到位imagecopyresampled功能的,试试吧,我也更新了上面的代码清单:

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

没有工作,显示的图像似乎指向'0,0',而不是'0,66'。 – yoda

+0

你可以发布你的更新代码。由于它对我来说非常合适,请参阅更新我的答案。 – danishgoel

+0

解决了这个问题,在'imagecopyresampled'上使用'$ width'和'$ height',我会坚持下去,在需要按比例显示时在'img'标签上定义'width'和'height'。不是最好的解决方案,但它也可以。我忘记的另一件事是我用小规模('2/3'或原来的)'jQuery'显示图像,因此给我一个奇怪的结果。谢谢,你的答案帮助:) – yoda

0

为什么不看看使用imagemagik;它非常适合图像处理,裁剪只是使用cropImage($ width,$ height,$ x,$ y)的简单例子。

+0

因为我的客户端的主机不具备安装该组件,客户拒绝改变主机和托管公司......还是不要说出来:) – yoda

+1

而事实上,PHP具有内置的图像处理功能。 – Bojangles

1

使用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; 
    } 
} 
+1

没有必要 - PHP可以做到这一点内部。请在发布您的答案之前做一点研究。 – Bojangles

+0

@JamWaffles:我知道我在说什么。我知道PHP可以自己做到这一点,我一直在使用GD2来裁剪和调整图像大小,但使用库会减轻开发人员的负担,因此开发人员可以专注于脚本的更大部分。 –

+1

确实如此,但如果开发人员只需要整个库中的一个函数,为什么还要增加额外的膨胀?如果他们需要重新使用它或稍后扩展它,PHP有类是有原因的:-) – Bojangles

0

这里,你可以通过在目标层面,将规模和作物从中心,保持纵横比,并且将扩展功能。用响应式设计的图片元素很容易实现。如果您更改目标尺寸,只需删除输出的文件,这将在不存在的情况下重新创建图像。

<?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'); ?>">