PHP图像处理--MagicWand生成缩略图(可加水印)

程序开发时经常会碰到用户上传图片生成小缩略图的需求,由于用户上传的图片长宽比例不一,按比例生成小图时如何整齐地显示在页面上成了问题。
考虑到图片要按比例缩放这是基本原则,显示的时候边缘补白会不会好些呢。如下:

图一 尺寸480x350


图二 尺寸270x360

如果我们设定生成图片尺寸为100x100,两张图片生成的小图如下:

这样的话,虽然原图一个长的一个宽的,但我们还是可以生成不变形的缩略图并整齐地显示在页面上。
原理: 新建一个背景图,然后把原图等比例缩放到不超过背景尺寸居中放置,生成需要的统一尺寸的缩略图片显示在页面上。
一向喜欢简洁,这么处理功能简单的模块更偏向于使用函数而不是类。
PHP生成这样的小缩略图函数如下:

<?php
/***********************************************************

   * Author ziming([email protected]) 2007-11-17

   * 本函数从源文件取出图象,成比例缩小,输出指定长宽的图片到目的文件
   * 如果原图尺寸比指定尺寸小,周围补充背景色;
   * 源文件格式:gif,jpg,png
   * 目的文件格式:同源文件格式
   * $srcFile: 源文件 (*.jpg/*.gif/*.png)
   * $dstDir: 目标文件目录(相对于域名存储目录的相对目录)
   * $dstFilename: 目标文件名 (一定不能带扩展名,自动添加同源文件相同的扩展名)
   * $Width: 目标图片宽度
   * $Height: 目标图片高度
   * $bgcolor: 缩放后图片背景填充色
   * $watermark: 水印图片文件名,为空表示不添加水印
   * $position: 水印图片位置(1=左上角,2=右上角,3=左下角,4=右下角)
   * $padding: 水印图片距边缘距离
   * 成功时返回目标文件信息数组
   * return array("filename"=>图片路径和名称,"dirname"=>图片目录,"basename"=>图片名(包括扩展名),"extension"=>图片扩展名);
   * 失败时返回空数组return array();

************************************************************/

function resize_image($srcFile, $dstDir, $dstFilename, $Width, $Height, $bgcolor = "#FFFFFF", $watermark = "", $position = 4, $padding = 20)
{
   $return_info = array();
   if (!is_file($srcFile))
   {
     return $return_info;
   }
   $size = @getimagesize($srcFile);

   //尺寸
     $srcW = $size[0];
     $srcH = $size[1];
   $srcR = $srcW/$srcH;
   $dstR = $Width/$Height;
   if ($Width<=0 || $Height <=0)
   {
     $newW = $srcW; //新图片高度
     $newH = $srcH; //新图片宽度
   }
   else
   {
     if($Width > $srcW)
     {
       if ($Height > $srcH)
       {
         $newW = $srcW;
         $newH = $srcH;
       }
       else
       {
         $newH = $Height;
         $newW = round($newH*$srcR);
       }
     }
     else
     {
       if ($dstR > $srcR)
       {
         $newH = $Height;
         $newW = round($newH*$srcR);
       }
       else
       {
         $newW = $Width;
         $newH = round($newW/$srcR);
       }
     }
   }
   $newL = round(($Width-$newW)/2); //新图片左边距
   $newT = round(($Height-$newH)/2); //新图片顶边距
   if ($newL < 0)
   {
     $newL = 0;
   }
   if ($newT < 0)
   {
     $newT = 0;
   }

   //类型
   switch ($size[2])
   {
     case 1:
       $im = @imagecreatefromgif($srcFile);
       $extension .= "gif";
       break;
     case 2:
       $im = @imagecreatefromjpeg($srcFile);
       $extension .= "jpg";
       break;
     case 3:
       $im = @imagecreatefrompng($srcFile);
       $extension .= "png";
       break;
     default:
       return $ret_info;
   }

   //缩放原图并合并到背景图上
   $bgR = hexdec(substr($bgcolor,1,2));
   $bgG = hexdec(substr($bgcolor,3,2));
   $bgB = hexdec(substr($bgcolor,5,2));
   if(@function_exists("imagecopyresampled"))
   {
     $newim = @imagecreatetruecolor($Width, $Height);
     $back = @imagecolorallocate($newim, $bgR, $bgG, $bgB);
     @imagefilledrectangle($newim, 0, 0, $Width - 1, $Height - 1, $back);
     @imagecopyresampled($newim, $im, $newL, $newT, 0, 0, $newW, $newH, $srcW, $srcH);
   }
   else
   {
     $newim = imagecreate($Width, $Height);
     @imagecolorallocate($newim, $bgR, $bgG, $bgB);
     imagecopyresized($newim, $im, $newL, $newT, 0, 0, $newW, $newH, $srcW, $srcH);
   }

   //处理水印图
   if ($watermark)
   {
     $padding = intval($padding);
     $wmsize = @getimagesize($watermark);
     if ($wmsize)
     {
       if ($position == 1)
       {
         $wmL = $padding;
         $wmT = $padding;
       }
       elseif ($position == 2)
       {
         $wmL = $Width-$padding-$wmsize[0];
         $wmT = $padding;
       }
       elseif ($position == 3)
       {
         $wmL = $padding;        
         $wmT = $Height-$padding-$wmsize[1];
       }
       else
       {
         $wmL = $Width-$padding-$wmsize[0];
         $wmT = $Height-$padding-$wmsize[1];
       }
       switch ($wmsize[2])
       {
         case 1:
           $wim = @imagecreatefromgif($watermark);
           break;
         case 2:
           $im = @imagecreatefromjpeg($watermark);
           break;
         case 3:
           $im = @imagecreatefrompng($watermark);
           break;
         default:
           return $ret_info;
       }
       @imagecopy($newim, $wim, $wmL, $wmT, 0, 0, $wsize[0], $wsize[1]);
     }
   }

   $dstFilename .= ".".$extension;
   switch ($size[2])
   {
     case 1:
       imagegif($newim,$dstFilename);
       break;
     case 2:
       imagejpeg($newim,$dstFilename);  
       break;
     case 3:
       imagepng($newim,$dstFilename);  
       break;
   }

   $return_info["filename"] = $dstDir.$dstFilename;
   $return_info["dirname"] = $dstDir;
   $return_info["basename"] = $dstFilename;
   $return_info["extension"] = $extension;
   return $return_info;
}

?>
水印图片建议使用PNG格式,可以透明生成的水印清晰度又高。
上面的函数要求PHP支持GD库并且存放缩略图的目标文件夹已经建立。
但使用GD库生成缩略图有个严重的问题,就是在处理有些手机或相机拍出的照片(暂且可以称这些照片为数据不完整或格式不符合标准图片)时会出现PHP占用内存超出服务器最大限制的现象,生成一张全黑的图片或直接失败。
好在有另外一个专业的图像处理工具ImageMagic可以使用,它的处理速度更快,并且一些不完整的图片也能轻松处理。
功能更完善的MagickWand缩略图生成函数如下:

<?php
/***********************************************************

   * Author ziming([email protected]) 2007-11-17

   * 本函数从源文件取出图象,成比例缩小,输出指定长宽的图片到目的文件
   * 如果原图尺寸比指定尺寸小,周围补充背景色;
   * 源文件格式:gif,jpg,png
   * 目的文件格式:同源文件格式
   * $srcFile: 源文件 (*.jpg/*.gif/*.png)
   * $dstDir: 目标文件目录(相对于域名存储目录的相对目录)
   * $dstFilename: 目标文件名 (一定不能带扩展名,自动添加同源文件相同的扩展名)
   * $Width: 目标图片宽度
   * $Height: 目标图片高度
   * $bgcolor: 缩放后图片背景填充色
   * $watermark: 水印图片文件名,为空表示不添加水印
   * $position: 水印图片位置(1=左上角,2=右上角,3=左下角,4=右下角)
   * $padding: 水印图片距边缘距离
   * 成功时返回目标文件信息数组
   * return array("filename"=>图片路径和名称,"dirname"=>图片目录,"basename"=>图片名(包括扩展名),"extension"=>图片扩展名);
   * 失败时返回空数组return array();

************************************************************/

function resize_image($srcFile, $dstDir, $dstFilename, $Width, $Height, $bgcolor = "#FFFFFF", $watermark = "", $position = 4, $padding = 20)
{
   $return_info = array();
   if (!is_file($srcFile))
   {
     return $return_info;
   }
   $mymagickwand = NewMagickWand();
   if (!MagickReadImage($mymagickwand, $srcFile))
   {
     return $return_info;
   }

   //尺寸
   $srcW = MagickGetImageWidth($mymagickwand);
     $srcH = MagickGetImageHeight($mymagickwand);
   $srcR = $srcW/$srcH;
   $dstR = $Width/$Height;
   if ($Width<=0 || $Height <=0)
   {
     $newW = $srcW; //新图片高度
     $newH = $srcH; //新图片宽度
   }
   else
   {
     if($Width > $srcW)
     {
       if ($Height > $srcH)
       {
         $newW = $srcW;
         $newH = $srcH;
       }
       else
       {
         $newH = $Height;
         $newW = round($newH*$srcR);
       }
     }
     else
     {
       if ($dstR > $srcR)
       {
         $newH = $Height;
         $newW = round($newH*$srcR);
       }
       else
       {
         $newW = $Width;
         $newH = round($newW/$srcR);
       }
     }
   }
   $newL = round(($Width-$newW)/2); //新图片左边距
   $newT = round(($Height-$newH)/2); //新图片顶边距
   if ($newL < 0)
   {
     $newL = 0;
   }
   if ($newT < 0)
   {
     $newT = 0;
   }

   //类型
   $srcT = MagickGetImageFormat($mymagickwand);
   if ($srcT == "JPEG")
   {
     $extension = "jpg";
   }
   elseif ($srcT == "GIF")
   {
     $extension = "gif";
   }
   elseif ($srcT == "PNG")
   {
     $extension = "png";
   }
   else
   {
     return $return_info;
   }

   //生成背景图
   $bgmagickwand = NewMagickWand();
   MagickNewImage($bgmagickwand,$Width,$Height,$bgcolor);
   MagickSetFormat($bgmagickwand,$srcT);

   //缩放原图并合并到背景图上
   MagickScaleImage($mymagickwand, $newW, $newH);
   MagickCompositeImage($bgmagickwand, $mymagickwand, MW_OverCompositeOp, $newL, $newT);

   //处理水印图
   if ($watermark && is_file($watermark))
   {
     MagickRemoveImage($mymagickwand);
     $padding = intval($padding);
     if (MagickReadImage($mymagickwand, $watermark))
     {
       if ($position == 1)
       {
         $wmL = $padding;
         $wmT = $padding;
       }
       elseif ($position == 2)
       {
         $wmL = $Width-$padding-MagickGetImageWidth($mymagickwand);
         $wmT = $padding;
       }
       elseif ($position == 3)
       {
         $wmL = $padding;        
         $wmT = $Height-$padding-MagickGetImageHeight($mymagickwand);
       }
       else
       {
         $wmL = $Width-$padding-MagickGetImageWidth($mymagickwand);
         $wmT = $Height-$padding-MagickGetImageHeight($mymagickwand);
       }
       MagickCompositeImage($bgmagickwand, $mymagickwand, MW_OverCompositeOp, $wmL,$wmT);
     }
   }

   $dstFilename .= ".".$extension;
   MagickWriteImage($bgmagickwand, $dstFilename);
   DestroyMagickWand($mymagickwand);
   DestroyMagickWand($bgmagickwand);

   $return_info["filename"] = $dstDir.$dstFilename;
   $return_info["dirname"] = $dstDir;
   $return_info["basename"] = $dstFilename;
   $return_info["extension"] = $extension;
   return $return_info;
}

?>
就像现在的PhilipDVD机一样,什么破碟烂碟盗版碟都能读取,超强纠错。
使用此函数生成的缩略图图像不变形,并且长和宽都是指定大小,再不会因为缩略图和原图长宽比例相同而各个缩略图的长宽比例不同使网页凌乱了。
PHP图像处理--MagicWand生成缩略图源码下载:
下载文件 (已下载 9 次)
点击这里下载文件: function_img.rar


既然讲到MagicWand就顺便把Windows下PHP5的MagicWand扩展库加载也说一下吧:
1、下载dll文件,放到PHP的extension_dir目录里。
下载文件 (已下载 6 次)
点击这里下载文件: magickwand_php5_dll.rar

2、打开PHP5的配置文件,添加以下三行内容。

extension=php_magickwand_dyn.dll
extension=php_magickwand_q8_st.dll
extension=php_magickwand_q16_st.dll

3、保存后重新启动Apache服务器。

你可能感兴趣的:(PHP图像处理--MagicWand生成缩略图(可加水印))